3

I have the following code running in a Windows Service that's been working for years without problems even under heavy concurrency:

CSharpCodeProvider codeProvider = new CSharpCodeProvider();           

CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = false;
parameters.GenerateInMemory = true;
parameters.OutputAssembly = outputAssemblyFile;    

CompilerResults results = codeProvider.CompileAssemblyFromFile(parameters, "file.cs");

if (results.Errors.Count > 0)
{
    Console.WriteLine("Compile ERROR");
}
else
{
    Console.WriteLine("Compile OK");        
    Console.WriteLine("Assembly Path:" + results.PathToAssembly);
    Console.WriteLine("Assembly Name:" + results.CompiledAssembly.FullName);        
}

Usually, when the code is successfully compiled, since parameters.GenerateInMemory is set to true, the results.PathToAssembly is null (as specified in the MSDN)

One of these days I started having an issue where sometimes the code was being successfully compiled but results.PathToAssembly was NOT null. Additionally, CompiledAssembly was returning a FileNotFoundException but when I checked the path indicated by results.PathToAssembly the assembly was actually there. I could not, however, make sure it was there at that specific moment.

I restarted the service and everything was back on track.

Is there any obvious reason for this to happen?

Thinking this could be some permission issue I tried to reproduce the issue by having the assembly already created and setting the file read-only, but that caused the compilation to fail.

4
  • Could there by chance been a slight permissions issue when results = was looking for the path to the specified assembly..? also where in the code are you releasing or disposing of the newly created objects.. I wounder if there could have been some caching issues in regards to causing this particular error.. Commented Jan 4, 2012 at 19:24
  • Why are you setting parameters.OutputAssembly if parameters.GenerateExecutable == false? Commented Jan 4, 2012 at 20:16
  • @M.Babcock i guess you mean parameters.GenerateInMemory = true. That's a good question. OutputAssembly is being set because we need the assembly (the actual file). I did not write the code, therefore I don't know about the GenerateInMemory part. Commented Jan 4, 2012 at 22:59
  • @DJKRAZE Check the last paragraph I just wrote. What other kind of permission issues could there be? I'm not releasing anything. This code is inside a method and that's all the code there is in it, I'm just letting the objects go out of scope. I'm not sure about the impact of this, but the Assembly resulting from Assembly.Load(results.CompiledAssembly) is being kept (never released) on purpose. Commented Jan 4, 2012 at 23:09

1 Answer 1

1

The way I read the documentation when GenerateInMemory==true the result of the compilation should be produced in memory, without generating a EXE or DLL file - hence result.PathToAssembly==null.

In this case setting OutputAssembly to something would still make sense: an assembly has a name even if it just lives in memory. GenerateExecutable tells the system to generate an EXE or a DLL, and so it should be ignored if the result is in memory.

This is the way I understand the theory - what happens in practice is that a DLL o EXE file is generated regardless of the value of GenerateInMemory, with the name specified by OutputAssembly and placed in the current directory.

Furthermore, it appears that the compiler does multiple operations on this file - delete/create/open/close.

This means that if the compiler code is called concurrently by multiple threads it can fail with either 'file not found' or 'file in use' errors, because the file operation on different thread will interfere with each other.

If the purpose of the code is to generate an assembly file on disk the solution would be:

parameters.GenerateExecutable = false; 
parameters.GenerateInMemory = false; 

and NOT specify OutputAssembly - in this case the system will auto-generate an unique name for the assembly (and the assembly DLL), avoiding conflicts between different threads. The path of the file is accessible in result.PathToAssembly.

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

1 Comment

Note that if you set GenerateExecutable = false and GenerateInMemory = true, the compiler will still generate an executable file based on the OutputAssembly path, ignoring the TempFiles parameter. That caused a permissions problem in my case because the executable, which supposedly wasn't being generated, was being generated to the current directory (eg. program files).

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.