1

I'm trying to dynamically compile code using CSharpCodeProvider. In the referenced assemblies, I'm adding a reference parameter for typeof(Program).Assembly.CodeBase), as was suggested here, but it doesn't work. I still get an error saying

error CS0006: Metadata file 'file:///C:/Code/MyProject/bin/MyProject.DLL' could not be found;

A file by that name does exist - the only difference is that the file extension shows lowercase in file explorer (".dll"), but otherwise, the filename from the error message matches the name and path of the dll I want to reference.

Any idea why the compiler would fail to see the referenced dll in this case?
Here is the relevant section of my code:

        CompilerResults result = null;
        CompilerParameters parms = new CompilerParameters();
        parms.GenerateExecutable = false;
        parms.GenerateInMemory = true;
        parms.OutputAssembly = "MyOutputAssembly";
        parms.ReferencedAssemblies.Add("System.dll");
        parms.ReferencedAssemblies.Add("System.Data.dll");
        parms.ReferencedAssemblies.Add("mscorlib.dll");
        parms.ReferencedAssemblies.Add(typeof(Program).Assembly.CodeBase); // Reference the current assembly

        // Lock because CSharpCodeProvider can only compile the code once per time slot
        lock (lockCompile)
        {
            using (CSharpCodeProvider codeProvider = new CSharpCodeProvider())
            {
                result = codeProvider.CompileAssemblyFromSource(parms, new string[] { code.ToString() });
            }
        }
Community
  • 1
  • 1
user756366
  • 467
  • 6
  • 24
  • Try using `typeof(Program).Assembly.Location` instead of `.CodeBase`. The `.Location` property on the assembly will return a straight-up path, whereas `.CodeBase` returns the location in URI form. I'm not sure but I think there might be scenarios related to loading remotely-hosted code where `.Location` doesn't give you anything and `.CodeBase` might give e.g. an `http` URI, but in your scenario, it sounds like your assembly is always going to be local, so you should always have a valid `.Location` value. :-) – Jonathan Gilbert Jan 23 '17 at 21:32
  • Done, and thanks :-) – Jonathan Gilbert Jan 23 '17 at 22:22
  • Thanks! That worked - if you add as an answer I'll mark as answer - and retrieved a very different path from .CodeBase - CodeBase retrieved the bin folder location, while Location got a temp directory: C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\Temporary ASP.NET Files\\myIISDirName\\65307448\\ec575f43\\assembly\\dl3\\d46288d9\\3e71eb5a_c275d201\\MyProject.dll. This post (http://stackoverflow.com/questions/864484/getting-the-path-of-the-current-assembly) seems to suggest that .Location pulls the address prior to shadow copying, and makes me a bit confused over when Location is safe... – user756366 Jan 23 '17 at 22:26

1 Answers1

2

Try using typeof(Program).Assembly.Location instead of .CodeBase. The .Location property on the assembly will return a straight-up path to the actual file that is loaded, whereas .CodeBase returns the caonical location in URI form. I'm not sure but I think there might be scenarios related to loading remotely-hosted code where .Location doesn't give you anything and .CodeBase might give e.g. an http URI, but in your scenario, it sounds like your assembly is always going to be local, so you should always have a valid .Location value. :-)

Jonathan Gilbert
  • 3,526
  • 20
  • 28
  • In the end I'm going with new System.Uri(Assembly.GetExecutingAssembly().EscapedCodeBase).LocalPath per the advantages posted at http://stackoverflow.com/questions/864484/getting-the-path-of-the-current-assembly, but in any case the "marked" answer above also worked and got me there! – user756366 Jan 23 '17 at 22:33