none
Using CSharpCodeProvider fails on loading referenced dll RRS feed

  • Question

  • I have a C# code that dynamically creates classes and runs them, in the code that is generated I am adding a reference to the current dll (the one that is creating them).

    The created classes fail compilation due to a missing dll

            var provider = new Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider();
            CompilerParameters cp = new CompilerParameters();
            cp.GenerateExecutable = false;
            cp.GenerateInMemory = true;
            cp.TreatWarningsAsErrors = false;
            cp.ReferencedAssemblies.Add(Assembly.GetAssembly(typeof(Enumerable)).Location);
            cp.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
            CompilerResults cr = provider.CompileAssemblyFromFile(cp, scripts.ToArray());
    

    The variable cr contains the following errors:

    (0, 0) Metadata file 'my dll' could not be opened -- Could not load file or assembly 'System.Collections.Immutable, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040) (0, 0) Metadata file 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll' could not be opened -- Could not load file or assembly 'System.Collections.Immutable, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040) (0, 0) Metadata file 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Runtime\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.dll' could not be opened -- Could not load file or assembly 'System.Collections.Immutable, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040) (0, 0) Metadata file 'C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll' could not be opened -- Could not load file or assembly 'System.Collections.Immutable, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

    I don't have a direct reference to 'System.Collections.Immutable' in my projects

    Thursday, April 4, 2019 4:53 AM

Answers

  • Let's use more generic names to try to clarify this. You have assembly A that is trying to compile some code to assembly B. Assembly A has some types that assembly B needs so you add a reference to assembly A from assembly B. But assembly A relies on assembly C and D as well. Furthermore the stuff that assembly B relies on in assembly A triggers a need by the compiler to also add a reference to assembly C. However you didn't provide this reference and the compiler cannot find the assembly so it fails the call. More specifically, in your case, it found the assembly but it needs version 1.2.0.0 and the version it found doesn't match so it fails the call.

    There are some possible workarounds here depending upon what is actually going on, which is hard to see in this case. The assembly that it is finding is coming from the GAC as it is part of .NET. However, at least on my machine, the version of this assembly for 4.7.2 is 1.1. That tells me you (or some assembly that you rely on) are probably getting this dependency via NuGet instead. Because the code dom provider isn't NuGet aware it won't know to fetch assemblies from there so it follows the standard compiler rules and thus doesn't find the assembly (or at least the correct version).

    The solution, in my opinion, is that you shouldn't rely on assembly A directly. In every case where you need to interact with code that may not exist at compile time it is recommended you create a "contracts" assembly. This assembly is used by your app but is referenced by any third party code (including your dynamically generated code). It should contain only the code (and minimal references) needed to get the third party code to compile. If at all possible you should be using interfaces and/or abstract classes to hide away the implementation details to minimize the dependencies. By doing this you both clarify what you are going to depend on but also protect the third party code from any changes in your implementation. So, to me, this is the correct approach.

    If for some reason that isn't going to work for you: a) make it work because it'll be easier long term, or b) you will have to work around the dependency issues. Since your app is clearly running (otherwise you couldn't compile the code) then the correct version of the Immutable assembly is sitting with your binary (ignoring the fact you may have a binding redirect). So to force the provider to see the "correct" version of the assembly you'll need to explicitly add the assemblies in your output directory to the list of referenced assemblies. The compiler will optimize away any references you don't use but it will allow the compiler to be able to find the assemblies that it is missing.


    Michael Taylor http://www.michaeltaylorp3.net

    Thursday, April 4, 2019 2:47 PM
    Moderator
  • I don't have a direct reference to 'System.Collections.Immutable' in my projects

    It doesn't mean that a DLL you are referencing or DLL the DLL is referencing, the dependency, is there when .NET tries to find the DLL or the dependency DLL that is not there.

    Could not load file or assembly 'System.Collections.Immutable, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference.

    With 'my dll',  you need to walk the chain and find out what is missing.

    http://www.dependencywalker.com/

    Thursday, April 4, 2019 10:07 PM

All replies

  • Let's use more generic names to try to clarify this. You have assembly A that is trying to compile some code to assembly B. Assembly A has some types that assembly B needs so you add a reference to assembly A from assembly B. But assembly A relies on assembly C and D as well. Furthermore the stuff that assembly B relies on in assembly A triggers a need by the compiler to also add a reference to assembly C. However you didn't provide this reference and the compiler cannot find the assembly so it fails the call. More specifically, in your case, it found the assembly but it needs version 1.2.0.0 and the version it found doesn't match so it fails the call.

    There are some possible workarounds here depending upon what is actually going on, which is hard to see in this case. The assembly that it is finding is coming from the GAC as it is part of .NET. However, at least on my machine, the version of this assembly for 4.7.2 is 1.1. That tells me you (or some assembly that you rely on) are probably getting this dependency via NuGet instead. Because the code dom provider isn't NuGet aware it won't know to fetch assemblies from there so it follows the standard compiler rules and thus doesn't find the assembly (or at least the correct version).

    The solution, in my opinion, is that you shouldn't rely on assembly A directly. In every case where you need to interact with code that may not exist at compile time it is recommended you create a "contracts" assembly. This assembly is used by your app but is referenced by any third party code (including your dynamically generated code). It should contain only the code (and minimal references) needed to get the third party code to compile. If at all possible you should be using interfaces and/or abstract classes to hide away the implementation details to minimize the dependencies. By doing this you both clarify what you are going to depend on but also protect the third party code from any changes in your implementation. So, to me, this is the correct approach.

    If for some reason that isn't going to work for you: a) make it work because it'll be easier long term, or b) you will have to work around the dependency issues. Since your app is clearly running (otherwise you couldn't compile the code) then the correct version of the Immutable assembly is sitting with your binary (ignoring the fact you may have a binding redirect). So to force the provider to see the "correct" version of the assembly you'll need to explicitly add the assemblies in your output directory to the list of referenced assemblies. The compiler will optimize away any references you don't use but it will allow the compiler to be able to find the assemblies that it is missing.


    Michael Taylor http://www.michaeltaylorp3.net

    Thursday, April 4, 2019 2:47 PM
    Moderator
  • I don't have a direct reference to 'System.Collections.Immutable' in my projects

    It doesn't mean that a DLL you are referencing or DLL the DLL is referencing, the dependency, is there when .NET tries to find the DLL or the dependency DLL that is not there.

    Could not load file or assembly 'System.Collections.Immutable, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference.

    With 'my dll',  you need to walk the chain and find out what is missing.

    http://www.dependencywalker.com/

    Thursday, April 4, 2019 10:07 PM