C# 在Azure上使用Codedom/CSharpCodeProvider进行动态编译

C# 在Azure上使用Codedom/CSharpCodeProvider进行动态编译,c#,.net,azure,codedom,C#,.net,Azure,Codedom,我正在使用以下代码动态编译一些代码,并将生成的DLL存储在Azure存储中 当我在本地运行它时,一切正常,但当使用Azure部署版本时,一切都不正常 我现在已经尝试了很多东西 这是我正在使用的最新版本。这不会引发任何错误,但不会存储DLL(存储方法工作正常,因为它在许多其他地方使用)。我假设权限有问题,或者DLL没有存储为文件 public Tuple<bool,string> compileAndStoreCodeAsDLL(Guid actionID, string action

我正在使用以下代码动态编译一些代码,并将生成的DLL存储在Azure存储中

当我在本地运行它时,一切正常,但当使用Azure部署版本时,一切都不正常

我现在已经尝试了很多东西

这是我正在使用的最新版本。这不会引发任何错误,但不会存储DLL(存储方法工作正常,因为它在许多其他地方使用)。我假设权限有问题,或者DLL没有存储为文件

public Tuple<bool,string> compileAndStoreCodeAsDLL(Guid actionID, string actionName, string actionMethod, string code)
    {
        string newFileName = "AncillaryTestMethods_" + actionName + ".dll";

        try
        {

            // Compile the code
            CSharpCodeProvider codeProvider = new CSharpCodeProvider();
            System.CodeDom.Compiler.CompilerParameters parameters = new CompilerParameters();
            parameters.GenerateExecutable = false;
            parameters.OutputAssembly = newFileName;
            parameters.GenerateInMemory = false;
            parameters.TempFiles = new TempFileCollection(".", true);
            parameters.ReferencedAssemblies.Add("System.dll");
            parameters.ReferencedAssemblies.Add("System.Core.dll");
            parameters.ReferencedAssemblies.Add("Microsoft.CSharp.dll");

            CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, code);

            MemoryStream stream = new MemoryStream();
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(stream, results.CompiledAssembly);

            // Store the code in the current firm's azure directory/ActionDLLs
            this.putFile(stream, newFileName, "ActionDLLs");

            // Return ok
            return new Tuple<bool, string>(true, null);
        }
        catch (Exception e)
        {
            // Return fail
            return new Tuple<bool, string>(true, e.Message);
        }     
    }
public Tuple compileAndStoreCodeAsDLL(Guid actionID、字符串actionName、字符串actionMethod、字符串代码)
{
字符串newFileName=“辅助测试方法”+actionName+“.dll”;
尝试
{
//编译代码
CSharpCodeProvider codeProvider=新的CSharpCodeProvider();
System.CodeDom.Compiler.CompilerParameters参数=新的CompilerParameters();
parameters.GenerateExecutable=false;
parameters.outputasembly=newFileName;
parameters.GenerateInMemory=false;
parameters.TempFiles=newtempfilecollection(“.”,true);
parameters.referencedAssembly.Add(“System.dll”);
parameters.referencedAssembly.Add(“System.Core.dll”);
parameters.referencedAssembly.Add(“Microsoft.CSharp.dll”);
CompilerResults results=codeProvider.CompileAsemblyFromSource(参数,代码);
MemoryStream stream=新的MemoryStream();
BinaryFormatter formatter=新的BinaryFormatter();
序列化(流、结果、编译汇编);
//将代码存储在当前公司的azure目录/ActionDLL中
这个.putFile(流,newFileName,“actiondll”);
//返回ok
返回新元组(true,null);
}
捕获(例外e)
{
//返回失败
返回新元组(true,例如Message);
}     
}
我从这段代码开始(这段代码在本地也有效):

public Tuple compileAndStoreCodeAsDLL(Guid actionID、字符串actionName、字符串actionMethod、字符串代码)
{
字符串newFileName=“辅助测试方法”+actionName+“.dll”;
尝试
{
//编译代码
CSharpCodeProvider codeProvider=新的CSharpCodeProvider();
System.CodeDom.Compiler.CompilerParameters参数=新的CompilerParameters();
parameters.GenerateExecutable=false;
parameters.outputasembly=newFileName;
parameters.referencedAssembly.Add(“System.dll”);
parameters.referencedAssembly.Add(“System.Core.dll”);
parameters.referencedAssembly.Add(“Microsoft.CSharp.dll”);
CompilerResults results=codeProvider.CompileAsemblyFromSource(参数,代码);
//将代码存储在当前公司的azure目录/ActionDLL中
这个.putFile(results.compiledsassembly.GetFile(newFileName)、newFileName、“actiondll”);
//返回ok
返回新元组(true,null);
}
捕获(例外e)
{
//返回失败
返回新元组(true,例如Message);
}     
}
但在Azure上引发了一个错误“生成Win32资源时出错:访问被拒绝。无法删除用于默认Win32资源的临时文件“d:windows\system32\inetsrv…tmp”-系统找不到指定的文件

这可能与Azure权限有关,因此我尝试了上面的代码


有人能建议对Azure中的函数进行任何修改吗?

经过17个小时的研究,我终于让它工作起来了。情况非常糟糕,我甚至尝试连接FluidSharp库中的Roslyn类,但它们自己也有一些重大问题

这里有三个核心问题:

  • Codedom似乎忽略了它自己的TempFiles属性,因此在Azure中,这些文件总是写入不可访问的inetsrv目录
  • Codedom的“GenerateInMemory”要么不起作用,要么它的名字完全误导人
  • 我需要以提升的权限启动我的WebRole(对此不是100%确定,但尚未删除代码)
  • 解决办法是:

  • 在Azure实例上创建一些本地存储空间
  • 将DLL写入本地存储器
  • 捕获与删除.TMP文件相关的任何错误并忽略它们。我发现这些错误意味着CompiledAssembly中没有数据,但DLL仍被写入本地存储
  • 不必为“生成内存”而烦恼
  • 提升权限

  • 希望这能为其他人省去一大堆麻烦!

    请注意,我刚刚意识到捕获异常时出现了一个错误,因为我要返回false,而不是true。我将在修复此问题后进行更新。在更正异常块以返回false后,该方法现在正确地报告另一个错误“对路径“d:\windows\system32\inetsrv\..tmp”的访问被拒绝。因此,另一个Azure许可问题。是否可以将临时文件写入我有权限访问的位置?我现在更改了tempfiles的位置,以便该行显示“parameters.tempfiles=new TempFileCollection(System.IO.Path.GetTempPath(),false);”。然而,这没有什么区别。。。仍然拒绝访问。哪一行实际抛出该异常?是否从源代码或行编译SemblyFromSource以将文件保存到本地目录?此代码是部署到网站、Web角色、工作者角色还是虚拟机?@Simon,引发异常的行是CompilerResults results=codeProvider.CompileAsemblyFromSource(参数、代码);现在我几乎可以肯定,这是由于内部没有正确使用CodeDom参数造成的。在Azure上,即使我将其设置为t,也始终存在拒绝访问的消息
            public Tuple<bool,string> compileAndStoreCodeAsDLL(Guid actionID, string actionName, string actionMethod, string code)
        {
            string newFileName = "AncillaryTestMethods_" + actionName + ".dll";
    
            try
            {
    
                // Compile the code
                CSharpCodeProvider codeProvider = new CSharpCodeProvider();
                System.CodeDom.Compiler.CompilerParameters parameters = new CompilerParameters();
                parameters.GenerateExecutable = false;
                parameters.OutputAssembly = newFileName;
                parameters.ReferencedAssemblies.Add("System.dll");
                parameters.ReferencedAssemblies.Add("System.Core.dll");
                parameters.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
    
                CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, code);
    
                // Store the code in the current firm's azure directory/ActionDLLs
                this.putFile(results.CompiledAssembly.GetFile(newFileName), newFileName, "ActionDLLs");
    
                // Return ok
                return new Tuple<bool, string>(true, null);
            }
            catch (Exception e)
            {
                // Return fail
                return new Tuple<bool, string>(true, e.Message);
            }     
        }