CodeDom.CompileAssemblyFromSource 抛出奇怪的错误

CodeDom.CompileAssemblyFromSource throws weird error

我的应用程序使用 CodeDom 从源文件中动态编译部分 javascript 代码。在 Windows 上,一切正常。但是 运行 Linux 上的应用最终抛出 InvalidOperationException,它没有提供有用的调试信息。这种情况的根本原因是什么?

我使用 Mono 4 在 Debian Jessie 上测试了该应用程序。0.x

private JScriptCodeProvider compiler = new JScriptCodeProvider();
private CompilerParameters parameters = new CompilerParameters();

参数:

parameters.ReferencedAssemblies.Add("System.dll");
parameters.GenerateExecutable = false;
parameters.GenerateInMemory = true;

编译:

// This line throws InvalidOperationException
var result = compiler.CompileAssemblyFromSource(parameters, scriptCode);

跟踪信息:

e   
{System.InvalidOperationException: Process has not been started.  
at System.Diagnostics.Process.get_ExitCode () [0x00015] in <filename
unknown>:0    

at (wrapper remoting-invoke-with-check)
System.Diagnostics.Process:get_ExitCode ()   

at System.CodeDom.Compiler.Executor.InternalExecWaitWithCapture
(System.String cmd, System.String currentDir,
System.CodeDom.Compiler.TempFileCollection tempFiles, System.String&
outputName, System.String& errorName) [0x000f1] in <filename
unknown>:0    

at System.CodeDom.Compiler.Executor.ExecWaitWithCapture
(System.String cmd, System.CodeDom.Compiler.TempFileCollection
tempFiles, System.String& outputName, System.String& errorName)
[0x00006] in <filename unknown>:0    

at System.CodeDom.Compiler.CodeCompiler.Compile
(System.CodeDom.Compiler.CompilerParameters options, System.String[]
fileNames, Boolean keepFiles) [0x0009c] in <filename unknown>:0    

at System.CodeDom.Compiler.CodeCompiler.FromSourceBatch
(System.CodeDom.Compiler.CompilerParameters options, System.String[]
sources) [0x0006b] in <filename unknown>:0    

at System.CodeDom.Compiler.CodeCompiler.System.CodeDom.Compiler.ICodeCompiler.CompileAssemblyFromSourceBatch
(System.CodeDom.Compiler.CompilerParameters options, System.String[]
sources) [0x00000] in <filename unknown>:0    

at System.CodeDom.Compiler.CodeDomProvider.CompileAssemblyFromSource
(System.CodeDom.Compiler.CompilerParameters options, System.String[]
sources) [0x00014] in <filename unknown>:0    

at ***.ScriptEngine.compile () [0x00036] in
***ScriptEngine.cs:139 }    
System.InvalidOperationException

Codedom 在 Linux 上有点奇怪。它的实现方式与在 Windows 上的实现方式不同,如果完全实现的话。如果你打算做一个跨平台的应用程序,我会建议 Mono 的 compiler as a service, or CS-Script's 更友好的实现。编译器即服务没有很好的文档记录,并且与 Microsoft 的运行时编译器不同。 CS-Script 是 Microsoft 和 Mono 的运行时编译器的包装器,它有很好的文档记录且简单明了。

由于某些原因,CodeDom 未能生成新进程以将源代码编译为临时程序集。我想在处理许可时出了点问题。请参阅以下跟踪:

converting method System.CodeDom.Compiler.Executor:ExecWaitWithCapture (string,System.CodeDom.Compiler.TempFileCollection,string&,string&)
Method System.CodeDom.Compiler.Executor:ExecWaitWithCapture (string,System.CodeDom.Compiler.TempFileCollection,string&,string&) emitted at 0x42060b90 to 0x42060bd5 (code length 69) [MyApp.exe]
converting method System.CodeDom.Compiler.Executor:InternalExecWaitWithCapture (string,string,System.CodeDom.Compiler.TempFileCollection,string&,string&)
Method System.CodeDom.Compiler.Executor:InternalExecWaitWithCapture (string,string,System.CodeDom.Compiler.TempFileCollection,string&,string&) emitted at 0x42060c00 to 0x42061080 (code length 1152) [MyApp.exe]
converting method (wrapper remoting-invoke-with-check) System.Diagnostics.Process:.ctor ()
Method (wrapper remoting-invoke-with-check) System.Diagnostics.Process:.ctor () emitted at 0x42061150 to 0x42061189 (code length 57) [MyApp.exe]
converting method System.Diagnostics.Process:.ctor ()
Method System.Diagnostics.Process:.ctor () emitted at 0x420611a0 to 0x420611b5 (code length 21) [MyApp.exe]
converting method (wrapper remoting-invoke-with-check) System.Diagnostics.Process:get_StartInfo ()
Method (wrapper remoting-invoke-with-check) System.Diagnostics.Process:get_StartInfo () emitted at 0x420611c0 to 0x42061222 (code length 98) [MyApp.exe]
converting method System.Diagnostics.Process:get_StartInfo ()
Method System.Diagnostics.Process:get_StartInfo () emitted at 0x42061240 to 0x420612d0 (code length 144) [MyApp.exe]
converting method System.Diagnostics.ProcessStartInfo:.ctor ()
Method System.Diagnostics.ProcessStartInfo:.ctor () emitted at 0x420612e0 to 0x42061302 (code length 34) [MyApp.exe]
converting method System.Diagnostics.ProcessStartInfo:.cctor ()
Method System.Diagnostics.ProcessStartInfo:.cctor () emitted at 0x42061310 to 0x42061338 (code length 40) [MyApp.exe]
converting method System.Diagnostics.ProcessStartInfo:set_FileName (string)
Method System.Diagnostics.ProcessStartInfo:set_FileName (string) emitted at 0x42061340 to 0x420613a0 (code length 96) [MyApp.exe]
converting method System.Diagnostics.ProcessStartInfo:set_CreateNoWindow (bool)
Method System.Diagnostics.ProcessStartInfo:set_CreateNoWindow (bool) emitted at 0x420613a0 to 0x420613bf (code length 31) [MyApp.exe]
converting method System.Diagnostics.ProcessStartInfo:set_UseShellExecute (bool)
Method System.Diagnostics.ProcessStartInfo:set_UseShellExecute (bool) emitted at 0x420613c0 to 0x420613df (code length 31) [MyApp.exe]
converting method System.Diagnostics.ProcessStartInfo:set_RedirectStandardOutput (bool)
Method System.Diagnostics.ProcessStartInfo:set_RedirectStandardOutput (bool) emitted at 0x420613e0 to 0x420613ff (code length 31) [MyApp.exe]
converting method System.Diagnostics.ProcessStartInfo:set_RedirectStandardError (bool)
Method System.Diagnostics.ProcessStartInfo:set_RedirectStandardError (bool) emitted at 0x42061400 to 0x4206141f (code length 31) [MyApp.exe]
converting method System.Diagnostics.ProcessStartInfo:set_WorkingDirectory (string)
Method System.Diagnostics.ProcessStartInfo:set_WorkingDirectory (string) emitted at 0x42061420 to 0x42061480 (code length 96) [MyApp.exe]
converting method (wrapper remoting-invoke-with-check) System.Diagnostics.Process:Start ()
Method (wrapper remoting-invoke-with-check) System.Diagnostics.Process:Start () emitted at 0x42061480 to 0x420614e2 (code length 98) [MyApp.exe]
converting method System.Diagnostics.Process:Start ()
Method System.Diagnostics.Process:Start () emitted at 0x42061500 to 0x42061555 (code length 85) [MyApp.exe]
converting method System.Diagnostics.Process:Start_common (System.Diagnostics.ProcessStartInfo,System.Diagnostics.Process)
Method System.Diagnostics.Process:Start_common (System.Diagnostics.ProcessStartInfo,System.Diagnostics.Process) emitted at 0x42061560 to 0x420616d0 (code length 368) [MyApp.exe]
converting method System.Diagnostics.ProcessStartInfo:get_FileName ()
Method System.Diagnostics.ProcessStartInfo:get_FileName () emitted at 0x42061730 to 0x4206175e (code length 46) [MyApp.exe]
converting method System.Diagnostics.ProcessStartInfo:get_StandardErrorEncoding ()
Method System.Diagnostics.ProcessStartInfo:get_StandardErrorEncoding () emitted at 0x42061760 to 0x42061774 (code length 20) [MyApp.exe]
converting method System.Diagnostics.ProcessStartInfo:get_StandardOutputEncoding ()
Method System.Diagnostics.ProcessStartInfo:get_StandardOutputEncoding () emitted at 0x42061780 to 0x42061794 (code length 20) [MyApp.exe]
converting method System.Diagnostics.ProcessStartInfo:get_UseShellExecute ()
Method System.Diagnostics.ProcessStartInfo:get_UseShellExecute () emitted at 0x420617a0 to 0x420617b4 (code length 20) [MyApp.exe]
converting method System.Diagnostics.Process:Start_noshell (System.Diagnostics.ProcessStartInfo,System.Diagnostics.Process)
Method System.Diagnostics.Process:Start_noshell (System.Diagnostics.ProcessStartInfo,System.Diagnostics.Process) emitted at 0x420617c0 to 0x420630d8 (code length 6424) [MyApp.exe]
converting method System.Diagnostics.ProcessStartInfo:get_HaveEnvVars ()
Method System.Diagnostics.ProcessStartInfo:get_HaveEnvVars () emitted at 0x420631c0 to 0x420631e9 (code length 41) [MyApp.exe]
converting method System.Diagnostics.ProcessStartInfo:get_RedirectStandardInput ()
Method System.Diagnostics.ProcessStartInfo:get_RedirectStandardInput () emitted at 0x420631f0 to 0x42063204 (code length 20) [MyApp.exe]
converting method System.Diagnostics.ProcessStartInfo:get_RedirectStandardOutput ()
Method System.Diagnostics.ProcessStartInfo:get_RedirectStandardOutput () emitted at 0x42063210 to 0x42063224 (code length 20) [MyApp.exe]
converting method System.Diagnostics.Process:get_IsWindows ()
Method System.Diagnostics.Process:get_IsWindows () emitted at 0x42063230 to 0x4206327a (code length 74) [MyApp.exe]
converting method (wrapper managed-to-native) System.IO.MonoIO:CreatePipe (intptr&,intptr&)
Method (wrapper managed-to-native) System.IO.MonoIO:CreatePipe (intptr&,intptr&) emitted at 0x42063280 to 0x4206330d (code length 141) [MyApp.exe]
converting method System.Diagnostics.ProcessStartInfo:get_RedirectStandardError ()
Method System.Diagnostics.ProcessStartInfo:get_RedirectStandardError () emitted at 0x42063310 to 0x42063324 (code length 20) [MyApp.exe]
converting method System.Diagnostics.Process:FillUserInfo (System.Diagnostics.ProcessStartInfo,System.Diagnostics.Process/ProcInfo&)
Method System.Diagnostics.Process:FillUserInfo (System.Diagnostics.ProcessStartInfo,System.Diagnostics.Process/ProcInfo&) emitted at 0x42063330 to 0x42063468 (code length 312) [MyApp.exe]
converting method System.Diagnostics.ProcessStartInfo:get_UserName ()
Method System.Diagnostics.ProcessStartInfo:get_UserName () emitted at 0x42063490 to 0x420634be (code length 46) [MyApp.exe]
converting method (wrapper managed-to-native) System.Diagnostics.Process:CreateProcess_internal (System.Diagnostics.ProcessStartInfo,intptr,intptr,intptr,System.Diagnostics.Process/ProcInfo&)
Method (wrapper managed-to-native) System.Diagnostics.Process:CreateProcess_internal (System.Diagnostics.ProcessStartInfo,intptr,intptr,intptr,System.Diagnostics.Process/ProcInfo&) emitted at 0x420634c0 to 0x42063570 (code   at System.Diagnostics.Process.get_ExitCode () [0x00000] in <filename unknown>:0 
  at (wrapper remoting-invoke-with-check) System.Diagnostics.Process:get_ExitCode ()
  at System.CodeDom.Compiler.Executor.InternalExecWaitWithCapture (System.String cmd, System.String currentDir, System.CodeDom.Compiler.TempFileCollection tempFiles, System.String& outputName, System.String& errorName) [0x00000] in <filename unknown>:0 
  at System.CodeDom.Compiler.Executor.ExecWaitWithCapture (System.String cmd, System.CodeDom.Compiler.TempFileCollection tempFiles, System.String& outputName, System.String& errorName) [0x00000] in <filename unknown>:0 
  at System.CodeDom.Compiler.CodeCompiler.Compile (System.CodeDom.Compiler.CompilerParameters options, System.String[] fileNames, Boolean keepFiles) [0x00000] in <filename unknown>:0 
  at System.CodeDom.Compiler.CodeCompiler.FromSourceBatch (System.CodeDom.Compiler.CompilerParameters options, System.String[] sources) [0x00000] in <filename unknown>:0 
  at System.CodeDom.Compiler.CodeCompiler.System.CodeDom.Compiler.ICodeCompiler.CompileAssemblyFromSourceBatch (System.CodeDom.Compiler.CompilerParameters options, System.String[] sources) [0x00000] in <filename unknown>:0 
  at System.CodeDom.Compiler.CodeDomProvider.CompileAssemblyFromSource (System.CodeDom.Compiler.CompilerParameters options, System.String[] sources) [0x00000] in <filename unknown>:0 
  at com.example.myapp.ScriptEngine.compile () [0x00000] in <filename unknown>:0 
length 176) [MyApp.exe]
converting method (wrapper managed-to-native) object:__icall_wrapper_mono_helper_ldstr (intptr,intptr)
Method (wrapper managed-to-native) object:__icall_wrapper_mono_helper_ldstr (intptr,intptr) emitted at 0x42063570 to 0x420635f9 (code length 137) [MyApp.exe]
converting method System.Diagnostics.ProcessStartInfo:get_Arguments ()
Method System.Diagnostics.ProcessStartInfo:get_Arguments () emitted at 0x42063600 to 0x4206362e (code length 46) [MyApp.exe]
converting method System.Diagnostics.ProcessStartInfo:get_WorkingDirectory ()
Method System.Diagnostics.ProcessStartInfo:get_WorkingDirectory () emitted at 0x42063630 to 0x4206365e (code length 46) [MyApp.exe]
converting method (wrapper managed-to-native) System.ComponentModel.Win32Exception:W32ErrorMessage (int)
Method (wrapper managed-to-native) System.ComponentModel.Win32Exception:W32ErrorMessage (int) emitted at 0x42063660 to 0x420636e1 (code length 129) [MyApp.exe]
converting method System.ComponentModel.Win32Exception:.ctor (int,string)
Method System.ComponentModel.Win32Exception:.ctor (int,string) emitted at 0x420636f0 to 0x42063727 (code length 55) [MyApp.exe]
converting method (wrapper remoting-invoke-with-check) System.Diagnostics.Process:get_ExitCode ()
Method (wrapper remoting-invoke-with-check) System.Diagnostics.Process:get_ExitCode () emitted at 0x42063740 to 0x420637a2 (code length 98) [MyApp.exe]
converting method System.Diagnostics.Process:get_ExitCode ()
Method System.Diagnostics.Process:get_ExitCode () emitted at 0x420637c0 to 0x42063864 (code length 164) [MyApp.exe]
converting method (wrapper managed-to-native) System.Diagnostics.StackTrace:get_trace (System.Exception,int,bool)
Method (wrapper managed-to-native) System.Diagnostics.StackTrace:get_trace (System.Exception,int,bool) emitted at 0x42063890 to 0x42063924 (code length 148) [MyApp.exe]

我觉得是时候尝试新事物了。然后我改变了我的代码如下:

#if LINUX
bool writeOk = true;
string tmpScriptName = String.Format("/tmp/com.myapp.script-{0}.js", Environment.TickCount);
try {
    File.WriteAllText(tmpScriptName, scriptCode);
} catch (Exception) {
    writeOk = false;
} finally {
    if (writeOk) {
        result = compiler.CompileAssemblyFromFile(parameters, tmpScriptName);
        try {
            File.Delete(tmpScriptName);
        } catch (Exception) { }
    }
}

#else
result = compiler.CompileAssemblyFromSource(parameters, scriptCode);
#endif

幸运的是,它又起作用了。