Adding Assemblies to BuildManager using CodeDOM causing intermittent errors

老子叫甜甜 提交于 2019-12-21 19:47:42

问题


I am using CodeDOM to create an in-memory assembly at run time like so:

 public Assembly Compile(CodeCompileUnit targetUnit)
    { 
        string path = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).AbsolutePath);
        var compilerParameters = new CompilerParameters
        {                 
            GenerateInMemory = true,
            IncludeDebugInformation = true,
            TreatWarningsAsErrors = true,
            WarningLevel = 4,
            CompilerOptions = "/nostdlib", 
        };           
        //For system.dll
        compilerParameters.ReferencedAssemblies.Add(typeof(System.Diagnostics.Debug).Assembly.Location);

        //For system.core.dll
        compilerParameters.ReferencedAssemblies.Add(typeof(System.IO.DirectoryInfo).Assembly.Location);

        //For Microsoft.CSharp.dll
        compilerParameters.ReferencedAssemblies.Add(typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.Location);
        compilerParameters.ReferencedAssemblies.Add(typeof(System.Runtime.CompilerServices.CallSite).Assembly.Location);

       //Add other assemblies as needed.

        var compilerResults = new CSharpCodeProvider()
        .CompileAssemblyFromDom(compilerParameters, targetUnit);
        if (compilerResults == null)
        {
            throw new InvalidOperationException("ClassCompiler did not return results.");
        }
        if(compilerResults.Errors.HasErrors)
        {
            var errors = string.Empty;
            foreach (CompilerError compilerError in compilerResults.Errors)
            {
                errors += compilerError.ErrorText + "\n";
            }
            Debug.Fail(errors);
            throw new InvalidOperationException("Errors occured while compiling dynamic classes:\n" + errors);
        }
        var dynamicAssembly = compilerResults.CompiledAssembly;
        return dynamicAssembly;
    }

The assembly generated above is added to the BuildManager at startup of an ASPNET host:

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(MyWebApp.MyStartup), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(MyWebApp.MyStartup), "Stop")]

namespace MyWebApp
{
    public static class MyStartup
    {
        public static void Start()
        {
            System.Reflection.Assembly assembly = GetDynamicAssembly();
            System.Web.Compilation.BuildManager.AddReferencedAssembly(assembly);
        }

        private static System.Reflection.Assembly GetDynamicAssembly()
        {
             //create and return dynamic assemblies using Codedom here
             var unit = GetCompilationUnit(); //elided for brevity
             return Compile(unit);
        }

        public static void Stop()
        {
            //do cleanup if needed
        }
    }
}

The above works mostly, but on occasion, I keep getting the following error with no clear indication as to the cause:

[NullReferenceException: Object reference not set to an instance of an object.]
   System.CodeDom.Compiler.CodeDomProvider.TryGetProbableCoreAssemblyFilePath(CompilerParameters parameters, String& coreAssemblyFilePath) +245
   Microsoft.CSharp.CSharpCodeGenerator.CmdArgsFromParameters(CompilerParameters options) +149
   Microsoft.CSharp.CSharpCodeGenerator.FromFileBatch(CompilerParameters options, String[] fileNames) +366
   Microsoft.CSharp.CSharpCodeGenerator.System.CodeDom.Compiler.ICodeCompiler.CompileAssemblyFromFileBatch(CompilerParameters options, String[] fileNames) +160
   System.CodeDom.Compiler.CodeDomProvider.CompileAssemblyFromFile(CompilerParameters options, String[] fileNames) +23
   System.Web.Compilation.AssemblyBuilder.Compile() +884
   System.Web.Compilation.BuildProvidersCompiler.PerformBuild() +9519768
   System.Web.Compilation.ApplicationBuildProvider.GetGlobalAsaxBuildResult(Boolean isPrecompiledApp) +9929000
   System.Web.Compilation.BuildManager.CompileGlobalAsax() +44
   System.Web.Compilation.BuildManager.EnsureTopLevelFilesCompiled() +269

[HttpException (0x80004005): Object reference not set to an instance of an object.]
   System.Web.Compilation.BuildManager.ReportTopLevelCompilationException() +62
   System.Web.Compilation.BuildManager.EnsureTopLevelFilesCompiled() +427
   System.Web.Compilation.BuildManager.CallAppInitializeMethod() +31
   System.Web.Hosting.HostingEnvironment.Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters, PolicyLevel policyLevel, Exception appDomainCreationException) +535

[HttpException (0x80004005): Object reference not set to an instance of an object.]
   System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +9930508
   System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +101
   System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +254

I looked at the source for CmdArgsFromParamters in csharpcodeprovider which calls into TryGetProbableCoreAssemblyFilePath and it seems to be looking for CoreAssemblyFileName to be set:

 string coreAssemblyFileName = options.CoreAssemblyFileName;
 if (String.IsNullOrWhiteSpace(options.CoreAssemblyFileName)) {
            string probableCoreAssemblyFilePath;
            if(CodeDomProvider.TryGetProbableCoreAssemblyFilePath(options, out probableCoreAssemblyFilePath)) {
                coreAssemblyFileName = probableCoreAssemblyFilePath;
            }

Do I need to explicity set CoreAssemblyFileName and if so what should this be set to? The documentation on this seems a bit sparse.

To reiterate, the error above occurs intermittently, and I'm puzzled as what the root cause is?

来源:https://stackoverflow.com/questions/28231162/adding-assemblies-to-buildmanager-using-codedom-causing-intermittent-errors

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!