X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem.Web%2FSystem.Web.Compilation%2FAppCodeCompiler.cs;h=71ac1d1452e111e5f1ed05c970e0d84f14726e29;hb=e63f092be1a94696370d0db9ce92b65d51fa493d;hp=86994858cd1bb678cb5111521fc146a61f957d84;hpb=677854916f9e462ad5f6c2d3f6fc293c180e1b30;p=mono.git diff --git a/mcs/class/System.Web/System.Web.Compilation/AppCodeCompiler.cs b/mcs/class/System.Web/System.Web.Compilation/AppCodeCompiler.cs index 86994858cd1..71ac1d1452e 100644 --- a/mcs/class/System.Web/System.Web.Compilation/AppCodeCompiler.cs +++ b/mcs/class/System.Web/System.Web.Compilation/AppCodeCompiler.cs @@ -44,15 +44,57 @@ using System.Web.Util; namespace System.Web.Compilation { + class AssemblyPathResolver + { + static Dictionary assemblyCache; + + static AssemblyPathResolver () + { + assemblyCache = new Dictionary (); + } + + public static string GetAssemblyPath (string assemblyName) + { + lock (assemblyCache) { + if (assemblyCache.ContainsKey (assemblyName)) + return assemblyCache [assemblyName]; + + Assembly asm = null; + Exception error = null; + if (assemblyName.IndexOf (',') != -1) { + try { + asm = Assembly.Load (assemblyName); + } catch (Exception e) { + error = e; + } + } + + if (asm == null) { + try { + asm = Assembly.LoadWithPartialName (assemblyName); + } catch (Exception e) { + error = e; + } + } + + if (asm == null) + throw new HttpException (String.Format ("Unable to find assembly {0}", assemblyName), error); + + assemblyCache.Add (assemblyName, asm.Location); + return asm.Location; + } + } + } + internal class AppCodeAssembly { - private List files; - private List units; + List files; + List units; - private string name; - private string path; - private bool validAssembly; - private string outputAssemblyName; + string name; + string path; + bool validAssembly; + string outputAssemblyName; public string OutputAssemblyName { @@ -121,13 +163,13 @@ namespace System.Web.Compilation // First make sure all the files are in the same // language - bool known; + bool known = false; foreach (string f in files) { known = true; language = null; extension = Path.GetExtension (f); - if (!CodeDomProvider.IsDefinedExtension (extension)) + if (String.IsNullOrEmpty (extension) || !CodeDomProvider.IsDefinedExtension (extension)) known = false; if (known) { language = CodeDomProvider.GetLanguageFromExtension(extension); @@ -156,16 +198,13 @@ namespace System.Web.Compilation } CodeDomProvider provider = null; - CompilationSection compilationSection = WebConfigurationManager.GetSection ("system.web/compilation") as CompilationSection; + CompilationSection compilationSection = WebConfigurationManager.GetWebApplicationSection ("system.web/compilation") as CompilationSection; if (compilerInfo == null) { if (!CodeDomProvider.IsDefinedLanguage (compilationSection.DefaultLanguage)) throw new HttpException ("Failed to retrieve default source language"); compilerInfo = CodeDomProvider.GetCompilerInfo (compilationSection.DefaultLanguage); if (compilerInfo == null || !compilerInfo.IsCodeDomProviderTypeValid) throw new HttpException ("Internal error while initializing application"); - provider = compilerInfo.CreateProvider (); - if (provider == null) - throw new HttpException ("A code provider error occurred while initializing application."); } provider = compilerInfo.CreateProvider (); @@ -186,12 +225,11 @@ namespace System.Web.Compilation parameters.ReferencedAssemblies.AddRange (binAssemblies); if (compilationSection != null) { - AssemblyName asmName; foreach (AssemblyInfo ai in compilationSection.Assemblies) if (ai.Assembly != "*") { try { - asmName = new AssemblyName (ai.Assembly); - parameters.ReferencedAssemblies.Add (asmName.Name); + parameters.ReferencedAssemblies.Add ( + AssemblyPathResolver.GetAssemblyPath (ai.Assembly)); } catch (Exception ex) { throw new HttpException ( String.Format ("Could not find assembly {0}.", ai.Assembly), @@ -208,6 +246,9 @@ namespace System.Web.Compilation bprovider.GenerateCode (abuilder); } } + + if (knownfiles.Count == 0 && unknownfiles.Count == 0 && units.Count == 0) + return; outputAssemblyName = (string)FileUtils.CreateTemporaryFile ( AppDomain.CurrentDomain.SetupInformation.DynamicBase, @@ -216,31 +257,40 @@ namespace System.Web.Compilation foreach (Assembly a in BuildManager.TopLevelAssemblies) parameters.ReferencedAssemblies.Add (a.Location); CompilerResults results = abuilder.BuildAssembly (parameters); - if (results.Errors.Count == 0) { - BuildManager.CodeAssemblies.Add (results.PathToAssembly); + if (results == null) + return; + + if (results.NativeCompilerReturnValue == 0) { + BuildManager.CodeAssemblies.Add (results.CompiledAssembly); BuildManager.TopLevelAssemblies.Add (results.CompiledAssembly); + HttpRuntime.WritePreservationFile (results.CompiledAssembly, name); } else { if (HttpContext.Current.IsCustomErrorEnabled) throw new HttpException ("An error occurred while initializing application."); throw new CompilationException (null, results.Errors, null); } } - - private BuildProvider GetBuildProviderFor (string file, BuildProviderCollection buildProviders) + + VirtualPath PhysicalToVirtual (string file) + { + return new VirtualPath (file.Replace (HttpRuntime.AppDomainAppPath, "/").Replace (Path.DirectorySeparatorChar, '/')); + } + + BuildProvider GetBuildProviderFor (string file, BuildProviderCollection buildProviders) { if (file == null || file.Length == 0 || buildProviders == null || buildProviders.Count == 0) return null; BuildProvider ret = buildProviders.GetProviderForExtension (Path.GetExtension (file)); if (ret != null && IsCorrectBuilderType (ret)) { - ret.SetVirtualPath (VirtualPathUtility.ToAppRelative (file)); + ret.SetVirtualPath (PhysicalToVirtual (file)); return ret; } return null; } - private bool IsCorrectBuilderType (BuildProvider bp) + bool IsCorrectBuilderType (BuildProvider bp) { if (bp == null) return false; @@ -273,7 +323,7 @@ namespace System.Web.Compilation internal class AppCodeCompiler { - static private bool _alreadyCompiled; + static bool _alreadyCompiled; internal static string DefaultAppCodeAssemblyName; // A dictionary that contains an entry per an assembly that will @@ -298,8 +348,8 @@ namespace System.Web.Compilation // Files for which exist BuildProviders but which have no // unambiguous language assigned to them (e.g. .wsdl files), are // built using the default website compiler. - private List assemblies; - string _bindir; + List assemblies; + string providerTypeName = null; public AppCodeCompiler () { @@ -309,12 +359,12 @@ namespace System.Web.Compilation bool ProcessAppCodeDir (string appCode, AppCodeAssembly defasm) { // First process the codeSubDirectories - CompilationSection cs = (CompilationSection) WebConfigurationManager.GetSection ("system.web/compilation"); + CompilationSection cs = (CompilationSection) WebConfigurationManager.GetWebApplicationSection ("system.web/compilation"); if (cs != null) { string aname; for (int i = 0; i < cs.CodeSubDirectories.Count; i++) { - aname = String.Format ("App_SubCode_{0}", cs.CodeSubDirectories[i].DirectoryName); + aname = String.Concat ("App_SubCode_", cs.CodeSubDirectories[i].DirectoryName); assemblies.Add (new AppCodeAssembly ( aname, Path.Combine (appCode, cs.CodeSubDirectories[i].DirectoryName))); @@ -331,28 +381,6 @@ namespace System.Web.Compilation return new CodeTypeReference (type); } - Type GetTypeFromBin (string typeName) - { - string bindir = BinDir; - if (!Directory.Exists (bindir)) - return null; - - string [] binDlls = Directory.GetFiles (bindir, "*.dll"); - Type ret = null; - foreach (string dll in binDlls) { - try { - Assembly asm = Assembly.LoadFrom (dll); - ret = asm.GetType (typeName, false); - if (ret != null) - break; - } catch (Exception) { - continue; - } - } - - return ret; - } - string FindProviderTypeName (ProfileSection ps, string providerName) { if (ps.Providers == null || ps.Providers.Count == 0) @@ -367,23 +395,13 @@ namespace System.Web.Compilation void GetProfileProviderAttribute (ProfileSection ps, CodeAttributeDeclarationCollection collection, string providerName) { - string providerTypeName; - if (String.IsNullOrEmpty (providerName)) providerTypeName = FindProviderTypeName (ps, ps.DefaultProvider); else providerTypeName = FindProviderTypeName (ps, providerName); if (providerTypeName == null) - throw new HttpException (String.Format ("Profile provider type not found: {0}", - providerTypeName)); - - Type type = Type.GetType (providerTypeName, false); - if (type == null) { - type = GetTypeFromBin (providerTypeName); - if (type == null) - throw new HttpException (String.Format ("Profile provider type not found: {0}", - providerTypeName)); - } + throw new HttpException (String.Format ("Profile provider type not defined: {0}", + providerName)); collection.Add ( new CodeAttributeDeclaration ( @@ -398,7 +416,7 @@ namespace System.Web.Compilation void GetProfileSettingsSerializeAsAttribute (ProfileSection ps, CodeAttributeDeclarationCollection collection, SerializationMode mode) { - string parameter = String.Format ("SettingsSerializeAs.{0}", mode.ToString ()); + string parameter = String.Concat ("SettingsSerializeAs.", mode.ToString ()); collection.Add ( new CodeAttributeDeclaration ( "SettingsSerializeAs", @@ -409,6 +427,32 @@ namespace System.Web.Compilation ); } + + void AddProfileClassGetProfileMethod (CodeTypeDeclaration profileClass) + { + CodeMethodReferenceExpression mref = new CodeMethodReferenceExpression ( + new CodeTypeReferenceExpression (typeof (System.Web.Profile.ProfileBase)), + "Create"); + CodeMethodInvokeExpression minvoke = new CodeMethodInvokeExpression ( + mref, + new CodeExpression[] { new CodeVariableReferenceExpression ("username") } + ); + CodeCastExpression cast = new CodeCastExpression (); + cast.TargetType = new CodeTypeReference ("ProfileCommon"); + cast.Expression = minvoke; + + CodeMethodReturnStatement ret = new CodeMethodReturnStatement (); + ret.Expression = cast; + + CodeMemberMethod method = new CodeMemberMethod (); + method.Name = "GetProfile"; + method.ReturnType = new CodeTypeReference ("ProfileCommon"); + method.Parameters.Add (new CodeParameterDeclarationExpression("System.String", "username")); + method.Statements.Add (ret); + method.Attributes = MemberAttributes.Public; + + profileClass.Members.Add (method); + } void AddProfileClassProperty (ProfileSection ps, CodeTypeDeclaration profileClass, ProfilePropertySettings pset) { @@ -484,10 +528,14 @@ namespace System.Web.Compilation } void BuildProfileClass (ProfileSection ps, string className, ProfilePropertySettingsCollection psc, - CodeNamespace ns, string baseClass, SortedList groupProperties) + CodeNamespace ns, string baseClass, bool baseIsGlobal, + SortedList groupProperties) { CodeTypeDeclaration profileClass = new CodeTypeDeclaration (className); - profileClass.BaseTypes.Add (new CodeTypeReference (baseClass)); + CodeTypeReference cref = new CodeTypeReference (baseClass); + if (baseIsGlobal) + cref.Options |= CodeTypeReferenceOptions.GlobalReference; + profileClass.BaseTypes.Add (cref); profileClass.TypeAttributes = TypeAttributes.Public; ns.Types.Add (profileClass); @@ -496,11 +544,12 @@ namespace System.Web.Compilation if (groupProperties != null && groupProperties.Count > 0) foreach (KeyValuePair group in groupProperties) AddProfileClassGroupProperty (group.Key, group.Value, profileClass); + AddProfileClassGetProfileMethod (profileClass); } string MakeGroupName (string name) { - return String.Format ("ProfileGroup{0}", name); + return String.Concat ("ProfileGroup", name); } // FIXME: there should be some validation of syntactic correctness of the member/class name @@ -521,7 +570,7 @@ namespace System.Web.Compilation ns.Imports.Add (new CodeNamespaceImport ("System.Web.Profile")); RootProfilePropertySettingsCollection props = ps.PropertySettings; - if (props == null || props.Count == 0) + if (props == null) return true; SortedList groupProperties = new SortedList (); @@ -530,13 +579,25 @@ namespace System.Web.Compilation groupName = MakeGroupName (pgs.Name); groupProperties.Add (groupName, pgs.Name); BuildProfileClass (ps, groupName, pgs.PropertySettings, ns, - "System.Web.Profile.ProfileGroupBase", null); + "System.Web.Profile.ProfileGroupBase", true, null); } string baseType = ps.Inherits; if (String.IsNullOrEmpty (baseType)) baseType = "System.Web.Profile.ProfileBase"; - BuildProfileClass (ps, "ProfileCommon", props, ns, baseType, groupProperties); + else { + string[] parts = baseType.Split (new char[] {','}); + if (parts.Length > 1) + baseType = parts [0].Trim (); + } + + bool baseIsGlobal; + if (baseType.IndexOf ('.') != -1) + baseIsGlobal = true; + else + baseIsGlobal = false; + + BuildProfileClass (ps, "ProfileCommon", props, ns, baseType, baseIsGlobal, groupProperties); return true; } @@ -548,17 +609,26 @@ namespace System.Web.Compilation // if (pb != null) // context.Profile = pb; // } + + public static bool HaveCustomProfile (ProfileSection ps) + { + if (ps == null || !ps.Enabled) + return false; + if (!String.IsNullOrEmpty (ps.Inherits) || (ps.PropertySettings != null && ps.PropertySettings.Count > 0)) + return true; + + return false; + } public void Compile () { if (_alreadyCompiled) return; - _alreadyCompiled = false; string appCode = Path.Combine (HttpRuntime.AppDomainAppPath, "App_Code"); - ProfileSection ps = WebConfigurationManager.GetSection ("system.web/profile") as ProfileSection; + ProfileSection ps = WebConfigurationManager.GetWebApplicationSection ("system.web/profile") as ProfileSection; bool haveAppCodeDir = Directory.Exists (appCode); - bool haveCustomProfile = ps != null ? ps.PropertySettings.Count > 0 : false; + bool haveCustomProfile = HaveCustomProfile (ps); if (!haveAppCodeDir && !haveCustomProfile) return; @@ -575,18 +645,72 @@ namespace System.Web.Compilation if (!haveCode) return; - + HttpRuntime.EnableAssemblyMapping (true); - string bindir = BinDir; - string[] binAssemblies = null; - if (Directory.Exists (bindir)) - binAssemblies = Directory.GetFiles (bindir, "*.dll"); + string[] binAssemblies = HttpApplication.BinDirectoryAssemblies; + foreach (AppCodeAssembly aca in assemblies) aca.Build (binAssemblies); + _alreadyCompiled = true; DefaultAppCodeAssemblyName = Path.GetFileNameWithoutExtension (defasm.OutputAssemblyName); + + RunAppInitialize (); + + if (haveCustomProfile && providerTypeName != null) { + if (Type.GetType (providerTypeName, false) == null) { + foreach (Assembly asm in BuildManager.TopLevelAssemblies) { + if (asm == null) + continue; + + if (asm.GetType (providerTypeName, false) != null) + return; + } + } else + return; + + if (HttpApplication.LoadTypeFromBin (providerTypeName) == null) + throw new HttpException (String.Format ("Profile provider type not found: {0}", + providerTypeName)); + } } - private bool CollectFiles (string dir, AppCodeAssembly aca) + // Documented (sort of...) briefly in: + // + // http://quickstarts.asp.net/QuickStartv20/aspnet/doc/extensibility.aspx + // http://msdn2.microsoft.com/en-us/library/system.web.hosting.virtualpathprovider.aspx + void RunAppInitialize () + { + MethodInfo mi = null, tmi; + Type[] types; + + foreach (Assembly asm in BuildManager.CodeAssemblies) { + types = asm.GetExportedTypes (); + if (types == null || types.Length == 0) + continue; + + foreach (Type type in types) { + tmi = type.GetMethod ("AppInitialize", + BindingFlags.Public | BindingFlags.Static | BindingFlags.IgnoreCase, + null, + Type.EmptyTypes, + null); + if (tmi == null) + continue; + + if (mi != null) + throw new HttpException ("The static AppInitialize method found in more than one type in the App_Code directory."); + + mi = tmi; + } + } + + if (mi == null) + return; + + mi.Invoke (null, null); + } + + bool CollectFiles (string dir, AppCodeAssembly aca) { bool haveFiles = false; @@ -602,21 +726,12 @@ namespace System.Web.Compilation curaca = a; break; } - CollectFiles (d, curaca); + if (CollectFiles (d, curaca)) + haveFiles = true; curaca = aca; } return haveFiles; } - - private string BinDir { - get { - if (_bindir != null) - return _bindir; - AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation; - _bindir = Path.Combine (setup.ApplicationBase, setup.PrivateBinPath); - return _bindir; - } - } } } #endif