0

For a while now I've been researching a safe and local way of allowing two different versions of the same assembly to be used by an application. There are several SO and online articles dealing with the issue, however there is a "gotcha" with every solution I read.

Let's imagine we have two 3rd party libraries (we have no control over) that use different versions of Newtonsoft (using Newtonsoft as an example, it can be any other dependency). We want each of the 3rd party libraries to use the Newtonsoft version they were built against. Following are some of the solutions I came across (from here and here):

Using a single version

Not ideal and sometimes not possible if each 3rd party library can work only against a specific version of a dependency.

Use GAC

Don't really want to.

Use AssemblyResolve

Will solve the main issue, however is considered unsafe to manually load two versions of the same assembly ourselves (rather than letting the runtime handle such task).

Use <codebase>

This is the most promising solution. The way I understand it is that I'm letting the runtime handle loading different versions of the same assembly, and my assumption is that it will do so in a safer way than me manually using AssemblyResolve. I just think of this as a LAC (Local Assembly Cache)™ . However, to my understanding putting this in the App.config of a class library (rather than executable) will be completely ignored. Here is my situation:

My app is developed in C++ and consumes .NET assemblies through C++/CLI. The .NET assemblies consumed are the ones that depend on 3rd party libraries, which themselves depend on different versions of the same assembly (i.e Newtonsoft). So really my question is there a way to use <codebase> when the main app/executable is developed with C++? Is there a way to get <codebase> to be used with a .NET class library?

If <codebase> cannot work when the main app is a C++ one, is my only option to install the latest version of the dependency (i.e Newtonsoft), and pray that it is backward compatible, so that 3rd party libraries that depend on older versions can still consume the latest version at runtime?

EDIT

I have followed Hans's suggestion by placing the <codeBase> in a config file that has the same name as the executable, which works fine. For example the config structure can be as follows:

<runtime>   
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
            <dependentAssembly>
                <assemblyIdentity name="DependencyName" culture="neutral" publicKeyToken="DependencyPublishToken" />          
                <codeBase version="1.0.0.0" href="DependencyName1.0.0.0/DependencyName.dll"/>     
                <codeBase version="2.0.0.0" href="DependencyName2.0.0.0/DependencyName.dll"/>               
            </dependentAssembly>
        </assemblyBinding>
    </runtime>

The only think I'd like to confirm (cannot find an answer anywhere) is this as safe as putting the assemblies in GAC? For example, would doing it this way still lead to issues mentioned here, or would it be safe because we're letting the runtime handle everything, and ensuring we only do the above for strong named assemblies?

Kakalokia
  • 3,191
  • 3
  • 24
  • 42
  • An app.exe.config file works just fine when app.exe is a native C++ executable. No real idea how you'd want to leverage codebase, you'd consider a bindingRedirect to force the newer version of the DLL to get used consistently. Putting the two DLLs in the GAC is another way. – Hans Passant Mar 28 '19 at 10:45
  • @HansPassant I was thinking of putting each different version of a dependency in a dedicated folder, and point each version to the relevant folder using . So if I have two different versions, there will be two different folders and two elements. – Kakalokia Mar 28 '19 at 11:34
  • @HansPassant bindingRedirect has the same drawback as using a single version as the 3rd party library may only work against a specific version (i.e newer versions are not backward compatible). – Kakalokia Mar 28 '19 at 11:35

0 Answers0