问题
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