如果将配置性文件编译为程序集,在执行的时候,它的性能将会高很多。
参看一下, System.Web.HttpApplicationFactory 中方法 CompileApplication()
private void CompileApplication() { // Get the Application Type and AppState from the global file _theApplicationType = BuildManager.GetGlobalAsaxType(); BuildResultCompiledGlobalAsaxType result = BuildManager.GetGlobalAsaxBuildResult(); if (result != null) { // Even if global.asax was already compiled, we need to get the collections // of application and session objects, since they are not persisted when // global.asax is compiled. Ideally, they would be, but since <object> tags // are only there for ASP compat, it's not worth the trouble. // Note that we only do this is the rare case where we know global.asax contains // <object> tags, to avoid always paying the price (VSWhidbey 453101) if (result.HasAppOrSessionObjects) { GetAppStateByParsingGlobalAsax(); } // Remember file dependencies _fileDependencies = result.VirtualPathDependencies; } if (_state == null) { _state = new HttpApplicationState(); } // Prepare to hookup event handlers via reflection ReflectOnApplicationType(); }
//------------------------------------------------------------------------------ // <copyright file="CodeDirectoryCompiler.cs" company="Microsoft"> // Copyright (c) Microsoft Corporation. All rights reserved. // </copyright> //----------------------------------------------------------------------------- namespace System.Web.Compilation { using System; using System.IO; using System.Collections; using System.CodeDom.Compiler; using System.Configuration; using System.Globalization; using System.Web.Configuration; using System.Reflection; using System.Web.Hosting; using System.Web.Util; using System.Web.UI; // The different types of directory that we treat as 'Code' (with minor differences) internal enum CodeDirectoryType { MainCode, // The main /code directory SubCode, // Code subdirectories registered to be compiled separately AppResources, // The /Resources directory LocalResources, // A /LocalResources directory (at any level) WebReferences // The /WebReferences directory } internal class CodeDirectoryCompiler { private VirtualPath _virtualDir; private CodeDirectoryType _dirType; private StringSet _excludedSubdirectories; private BuildProvidersCompiler _bpc; private BuildProviderSet _buildProviders = new BuildProviderSet(); private bool _onlyBuildLocalizedResources; static internal BuildResultMainCodeAssembly _mainCodeBuildResult; internal static bool IsResourceCodeDirectoryType(CodeDirectoryType dirType) { return dirType == CodeDirectoryType.AppResources || dirType == CodeDirectoryType.LocalResources; } internal static Assembly GetCodeDirectoryAssembly(VirtualPath virtualDir, CodeDirectoryType dirType, string assemblyName, StringSet excludedSubdirectories, bool isDirectoryAllowed) { string physicalDir = virtualDir.MapPath(); if (!isDirectoryAllowed) { // The directory should never exist in a precompiled app if (Directory.Exists(physicalDir)) { throw new HttpException(SR.GetString( SR.Bar_dir_in_precompiled_app, virtualDir)); } } bool supportLocalization = IsResourceCodeDirectoryType(dirType); // Determine the proper cache key based on the type of directory we're processing string cacheKey = assemblyName; // Try the cache first BuildResult result = BuildManager.GetBuildResultFromCache(cacheKey); Assembly resultAssembly = null; // If it's cached, just return it if (result != null) { // It should always be a BuildResultCompiledAssembly, though if there is // a VirtualPathProvider doing very bad things, it may not (VSWhidbey 341701) Debug.Assert(result is BuildResultCompiledAssembly); if (result is BuildResultCompiledAssembly) { // If it's the main code assembly, keep track of it so we can later call // the AppInitialize method if (result is BuildResultMainCodeAssembly) { Debug.Assert(dirType == CodeDirectoryType.MainCode); Debug.Assert(_mainCodeBuildResult == null); _mainCodeBuildResult = (BuildResultMainCodeAssembly) result; } resultAssembly = ((BuildResultCompiledAssembly)result).ResultAssembly; if (!supportLocalization) return resultAssembly; // We found a preserved resource assembly. However, we may not be done, // as the culture specific files may have changed. // But don't make any further checks if the directory is not allowed (precomp secenario). // In that case, we should always return the assembly (VSWhidbey 533498) if (!isDirectoryAllowed) return resultAssembly; BuildResultResourceAssembly buildResultResAssembly = (BuildResultResourceAssembly)result; string newResourcesDependenciesHash = HashCodeCombiner.GetDirectoryHash(virtualDir); // If the resources hash (which includes satellites) is up to date, we're done if (newResourcesDependenciesHash == buildResultResAssembly.ResourcesDependenciesHash) return resultAssembly; } } // If app was precompiled, don't attempt compilation if (!isDirectoryAllowed) return null; // Check whether the virtual dir is mapped to a different application, // which we don't support (VSWhidbey 218603). But don't do this for LocalResource (VSWhidbey 237935) if (dirType != CodeDirectoryType.LocalResources && !StringUtil.StringStartsWithIgnoreCase(physicalDir, HttpRuntime.AppDomainAppPathInternal)) { throw new HttpException(SR.GetString(SR.Virtual_codedir, virtualDir.VirtualPathString)); } // If the directory doesn't exist, we may be done if (!Directory.Exists(physicalDir)) { // We're definitely done if it's not the main code dir if (dirType != CodeDirectoryType.MainCode) return null; // If it is the main code dir, we're only done is there is no profile to compile // since the profice gets built as part of the main assembly. if (!ProfileBuildProvider.HasCompilableProfile) return null; } // Otherwise, compile it BuildManager.ReportDirectoryCompilationProgress(virtualDir); DateTime utcStart = DateTime.UtcNow; CodeDirectoryCompiler cdc = new CodeDirectoryCompiler(virtualDir, dirType, excludedSubdirectories); string outputAssemblyName = null; if (resultAssembly != null) { // If resultAssembly is not null, we are in the case where we just need to build // the localized resx file in a resources dir (local or global) Debug.Assert(supportLocalization); outputAssemblyName = resultAssembly.GetName().Name; cdc._onlyBuildLocalizedResources = true; } else { outputAssemblyName = BuildManager.GenerateRandomAssemblyName(assemblyName); } BuildProvidersCompiler bpc = new BuildProvidersCompiler(virtualDir, supportLocalization, outputAssemblyName); cdc._bpc = bpc; // Find all the build provider we want to compile from the code directory cdc.FindBuildProviders(); // Give them to the BuildProvidersCompiler bpc.SetBuildProviders(cdc._buildProviders); // Compile them into an assembly CompilerResults results = bpc.PerformBuild(); // Did we just compile something? if (results != null) { Debug.Assert(result == null); Debug.Assert(resultAssembly == null); // If there is already a loaded module with the same path, try to wait for it to be unloaded. // Otherwise, we would end up loading this old assembly instead of the new one (VSWhidbey 554697) DateTime waitLimit = DateTime.UtcNow.AddMilliseconds(3000); for (;;) { IntPtr hModule = UnsafeNativeMethods.GetModuleHandle(results.PathToAssembly); if (hModule == IntPtr.Zero) break; Debug.Trace("CodeDirectoryCompiler", results.PathToAssembly + " is already loaded. Waiting a bit"); System.Threading.Thread.Sleep(250); // Stop trying if the timeout was reached if (DateTime.UtcNow > waitLimit) { Debug.Trace("CodeDirectoryCompiler", "Timeout waiting for old assembly to unload: " + results.PathToAssembly); throw new HttpException(SR.GetString(SR.Assembly_already_loaded, results.PathToAssembly)); } } resultAssembly = results.CompiledAssembly; } // It is possible that there was nothing to compile (and we're not in the // satellite resources case) if (resultAssembly == null) return null; // For the main code directory, use a special BuildResult that takes care of // calling AppInitialize if it finds one if (dirType == CodeDirectoryType.MainCode) { // Keep track of it so we can later call the AppInitialize method _mainCodeBuildResult = new BuildResultMainCodeAssembly(resultAssembly); result = _mainCodeBuildResult; } else if (supportLocalization) { result = new BuildResultResourceAssembly(resultAssembly); } else { result = new BuildResultCompiledAssembly(resultAssembly); } result.VirtualPath = virtualDir; // If compilations are optimized, we need to include the right dependencies, since we can no longer // rely on everything getting wiped out when something in App_Code changes. // But don't do this for local resources, since they have their own special way of // dealing with dependencies (in BuildResultResourceAssembly.ComputeSourceDependenciesHashCode). // It's crucial *not* to do it as it triggers a tricky infinite recursion due to the fact // that GetBuildResultFromCacheInternal calls EnsureFirstTimeDirectoryInitForDependencies if // there is at least one dependency if (BuildManager.OptimizeCompilations && dirType != CodeDirectoryType.LocalResources) { result.AddVirtualPathDependencies(new SingleObjectCollection(virtualDir.AppRelativeVirtualPathString)); } // Top level assembly should not be cached to memory. But LocalResources are *not* // top level files, and do benefit from memory caching if (dirType != CodeDirectoryType.LocalResources) result.CacheToMemory = false; // Cache it for next time BuildManager.CacheBuildResult(cacheKey, result, utcStart); return resultAssembly; } // Call the AppInitialize method in the Code assembly if there is one internal static void CallAppInitializeMethod() { if (_mainCodeBuildResult != null) _mainCodeBuildResult.CallAppInitializeMethod(); } internal const string sourcesDirectoryPrefix = "Sources_"; internal static void GetCodeDirectoryInformation( VirtualPath virtualDir, CodeDirectoryType dirType, StringSet excludedSubdirectories, int index, out Type codeDomProviderType, out CompilerParameters compilerParameters, out string generatedFilesDir) { // Compute the full path to the directory we'll use to generate all // the code files generatedFilesDir = HttpRuntime.CodegenDirInternal + "\\" + sourcesDirectoryPrefix + virtualDir.FileName; bool supportLocalization = IsResourceCodeDirectoryType(dirType); // the index is used to retrieve the correct referenced assemblies BuildProvidersCompiler bpc = new BuildProvidersCompiler(virtualDir, supportLocalization, generatedFilesDir, index); CodeDirectoryCompiler cdc = new CodeDirectoryCompiler(virtualDir, dirType, excludedSubdirectories); cdc._bpc = bpc; // Find all the build provider we want to compile from the code directory cdc.FindBuildProviders(); // Give them to the BuildProvidersCompiler bpc.SetBuildProviders(cdc._buildProviders); // Generate all the sources into the directory generatedFilesDir bpc.GenerateSources(out codeDomProviderType, out compilerParameters); } private CodeDirectoryCompiler(VirtualPath virtualDir, CodeDirectoryType dirType, StringSet excludedSubdirectories) { _virtualDir = virtualDir; _dirType = dirType; _excludedSubdirectories = excludedSubdirectories; } private void FindBuildProviders() { // If we need to build the profile, add its build provider if (_dirType == CodeDirectoryType.MainCode && ProfileBuildProvider.HasCompilableProfile) { _buildProviders.Add(ProfileBuildProvider.Create()); } VirtualDirectory vdir = HostingEnvironment.VirtualPathProvider.GetDirectory(_virtualDir); ProcessDirectoryRecursive(vdir, true /*topLevel*/); } private void AddFolderLevelBuildProviders(VirtualDirectory vdir, FolderLevelBuildProviderAppliesTo appliesTo) { BuildManager.AddFolderLevelBuildProviders(_buildProviders, vdir.VirtualPathObject, appliesTo, _bpc.CompConfig, _bpc.ReferencedAssemblies); } private void ProcessDirectoryRecursive(VirtualDirectory vdir, bool topLevel) { // If it's a WebReferences directory, handle it using a single WebReferencesBuildProvider // instead of creating a different BuildProvider for each file. if (_dirType == CodeDirectoryType.WebReferences) { // Create a build provider for the current directory BuildProvider buildProvider = new WebReferencesBuildProvider(vdir); buildProvider.SetVirtualPath(vdir.VirtualPathObject); _buildProviders.Add(buildProvider); AddFolderLevelBuildProviders(vdir, FolderLevelBuildProviderAppliesTo.WebReferences); } else if (_dirType == CodeDirectoryType.AppResources) { AddFolderLevelBuildProviders(vdir, FolderLevelBuildProviderAppliesTo.GlobalResources); } else if (_dirType == CodeDirectoryType.LocalResources) { AddFolderLevelBuildProviders(vdir, FolderLevelBuildProviderAppliesTo.LocalResources); } else if (_dirType == CodeDirectoryType.MainCode || _dirType == CodeDirectoryType.SubCode) { AddFolderLevelBuildProviders(vdir, FolderLevelBuildProviderAppliesTo.Code); } // Go through all the files in the directory foreach (VirtualFileBase child in vdir.Children) { if (child.IsDirectory) { // If we are at the top level of this code directory, and the current // subdirectory is in the exclude list, skip it if (topLevel && _excludedSubdirectories != null && _excludedSubdirectories.Contains(child.Name)) { continue; } // Exclude the special FrontPage directory (VSWhidbey 116727) if (child.Name == "_vti_cnf") continue; ProcessDirectoryRecursive(child as VirtualDirectory, false /*topLevel*/); continue; } // Don't look at individual files for WebReferences directories if (_dirType == CodeDirectoryType.WebReferences) continue; // Skip neutral files if _onlyBuildLocalizedResources is true if (IsResourceCodeDirectoryType(_dirType)) { if (_onlyBuildLocalizedResources && System.Web.UI.Util.GetCultureName(child.VirtualPath) == null) { continue; } } BuildProvider buildProvider = BuildManager.CreateBuildProvider(child.VirtualPathObject, (IsResourceCodeDirectoryType(_dirType)) ? BuildProviderAppliesTo.Resources : BuildProviderAppliesTo.Code, _bpc.CompConfig, _bpc.ReferencedAssemblies, false /*failIfUnknown*/); // Non-supported file type if (buildProvider == null) continue; // For Page resources, don't generate a strongly typed class if (_dirType == CodeDirectoryType.LocalResources && buildProvider is BaseResourcesBuildProvider) { ((BaseResourcesBuildProvider)buildProvider).DontGenerateStronglyTypedClass(); } _buildProviders.Add(buildProvider); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
抄吧。
另 : http://blogs.msdn.com/b/digitalnetbizz/archive/2004/01/31/create-assembly-in-memory-and-run-it.aspx
using System; using Specialized = System.Collections.Specialized; using Reflection = System.Reflection; using CSharp = Microsoft.CSharp; using CodeDom = System.CodeDom.Compiler; public sealed class TestCompile { static string ScriptCodeToCompileInMem = "public class Script {public void ScriptExecute(){System.Console.WriteLine(123);} }"; public static void Main() { TestCompile tc = new TestCompile(); tc.Execute(TestCompile.ScriptCodeToCompileInMem); } public void Execute(string scriptCode) { string [] source = new string[1]; source[0] = scriptCode; CSharp.CSharpCodeProvider cscp = new CSharp.CSharpCodeProvider(); this.Compile(cscp, source[0]); } private void Compile(CodeDom.CodeDomProvider provider, string source) { CodeDom.CompilerParameters param = new CodeDom.CompilerParameters(); param.GenerateExecutable = false; param.IncludeDebugInformation = false; param.GenerateInMemory = true; CodeDom.ICodeCompiler cc = provider.CreateCompiler(); CodeDom.CompilerResults cr = cc.CompileAssemblyFromSource(param, source); Specialized.StringCollection output = cr.Output; if(cr.Errors.Count !=0) { System.Console.WriteLine("Error invoking scripts."); CodeDom.CompilerErrorCollection es = cr.Errors; foreach(CodeDom.CompilerError s in es) System.Console.WriteLine(s.ErrorText); } else { object o = cr.CompiledAssembly.CreateInstance("Script"); System.Type type = o.GetType(); type.InvokeMember ("ScriptExecute", Reflection.BindingFlags.InvokeMethod | Reflection.BindingFlags.Default, null, o, null); } } }