2

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?

5
  • Please note I've just realised there is an error when I catch the exception in that I am meant to return false, not true. I will update once I have fixed this. Commented Jan 29, 2015 at 15:17
  • After correcting the exception block to return false, the method now correctly reports another error "Access to the path 'd:\windows\system32\inetsrv\....tmp' is denied. So another Azure permission issue. Is it possible to write the temporary file to a location that I DO have permission to? Commented Jan 29, 2015 at 15:43
  • I have now changed the tempfiles location so that the line reads "parameters.TempFiles = new TempFileCollection(System.IO.Path.GetTempPath(), false);". However, this makes no difference... still Access Denied. Commented Jan 29, 2015 at 17:23
  • What line actually throws that Exception? CompileAssemblyFromSource or the line to save the file to a directory locally? Is this code deployed to a Website, Web Role, Worker Role or a Virtual Machine? Commented Jan 29, 2015 at 22:28
  • @Simon, the line that throws the exception is CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, code); I'm almost sure now that this is caused by CodeDom parameters not being used correctly internally. On Azure there is always an Access Denied message even if I set it to write to the temp area. I've even started to look at other solutions such as Mono and Roslyn. But Roslyn isn't ready yet and I haven't yet figured out if Mono will do what I want. It's a Web role btw. Commented Jan 30, 2015 at 9:40

1 Answer 1

3

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!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.