简体   繁体   中英

Dynamic compilation using Codedom/CSharpCodeProvider on Azure

I am using the following code to compile some code dynamically and store the resulting DLL in Azure storage.

It all works fine when I run this locally, but does not work when using the Azure-deployed version.

I have tried quite a few things now.

This is the latest version that I am using. This doesn't throw any errors but doesn't store the DLL (the storing method works fine as it is used in many other places). I assume there is a problem with permissions OR the fact that the DLL is not being stored as a file.

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);
        }     
    }

I started with this code (which also worked locally):

        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);
        }     
    }

But on Azure threw an error "Error Generating Win32 resource: Access is denied. Unable to delete temporary file 'd:windows\\system32\\inetsrv...tmp' used for default Win32 resource -- the system cannot find the file specified.

This is presumably Azure permissions related, so I tried the code above.

Can anyone suggest any changes to make this function work in Azure?

After something like 17 hours on this, I have finally got it working. The situation was so dire that I even tried hooking in to the Roslyn classes in the FluidSharp libraries but they had major issues of their own.

There were three core issues here:

  1. Codedom seems to ignore its own TempFiles attribute, so in Azure these are always written to the inaccessible inetsrv directory.
  2. Codedom's "GenerateInMemory" either doesn't work or its name is utterly misleading.
  3. I needed to start my WebRole with elevated permissions (not 100% sure on this one, but haven't yet removed the code)

The solutions were:

  1. Create some Local Storage space on the Azure instance.
  2. Write the DLL to the Local Storage.
  3. Catch any errors associated to deleting .TMP files and ignore them. I found that these errors meant that CompiledAssembly had no data in it, but the DLL was still written out to Local Storage.
  4. Don't bother with GenerateInMemory
  5. Elevate the permissions

Hope this saves someone else a load of hassle!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM