0

I have two different projects and both use Newtonsoft.Json from NuGet.

  • Project A uses the version 9.0.1.
  • Project B uses the version 11.0.1.

When building the projects, one dll is overwriting the other dll, because they are both being compiled in the same folder.

How can I redirect the compilation for the dll's in seperate files and how can I say that Project A uses 9.0.1 and Project B uses 11.0.1?

It would be great to have a folder "Newtonsoft" and there are 2 folders "11" and "9". In those folders are the specific versions. (If there's another solution, then I'm also fine with the other one).

Project A and Project B are both "Plugins", which are being used by an application by me, which includes those plugins from a Plugin-Folder.. This means I currently have an application which uses the following dll's (they are all in one folder):

  • Project_A.dll
  • Project_B.dll
  • NewtonSoft.Json.dll (either 9.0.1 or 11.0.1)

ProjectA.dll

This is my app.config

Project A:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-11.0.0.0" newVersion="11.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="YamlDotNet" publicKeyToken="ec19458f3c15af5e" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

Project B:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-11.0.0.0" newVersion="11.0.0.0" />
        <codeBase version="11.0.0.1" href="Newtonsoft.Json.dll" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" /></startup></configuration>
Rudi
  • 926
  • 2
  • 19
  • 38
  • 6
    Have you considered changing both projects to use the same version? – mjwills Sep 18 '19 at 14:04
  • @mjwills I have, but Project B uses some functionalities, which are only available in 11.0.1. In Project A I'm using anoter Nuget Package, which only works with 9.0.1. Therefore I need both dll's, since I can't upgrade/downgrade the versions. – Rudi Sep 18 '19 at 14:21
  • 1
    The bindingRedirect must be applied to the project that uses these DLLs. So your EXE project, not the library projects. – Hans Passant Sep 18 '19 at 14:38
  • 1
    Answers belong in *answers*, not edited into the question. If you have an answer, post it as one and (after the cooldown period) accept it. – Damien_The_Unbeliever Sep 19 '19 at 07:22

2 Answers2

0

You can place your assemblies in different folders (not necessarily directly in the bin folder) and use the codeBase element:

<configuration>
<runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
        <dependentAssembly>
            <assemblyIdentity name="Some.API" publicKeyToken="12ab3cd4e5f6abcd"
              culture="neutral" />
            <codeBase version="1.0.0.0" href="v1\Some.API.dll" />
            <codeBase version="2.0.0.0" href="v2\Some.API.dll" />
            <!-- INFO: The version attribute represents an assembly 
                       version which doesn't always have to match the 
                       NuGet package version.
                       The codebase attribute can be anywhere on 
                       the local intranet or the Internet. -->
        </dependentAssembly>
    </assemblyBinding>
</runtime>

Source: https://devnet.kentico.com/articles/referencing-multiple-versions-of-the-same-assembly-in-a-single-application

Daniel Crha
  • 675
  • 5
  • 13
0

SOLVED

Got it working by doing it like this:

Before I use any method/class of Newtonsfot.Json, I use the following two lines:

//The AssemblyResolve event is called when the common language runtime tries to bind to the assembly and fails.
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(currentDomain_AssemblyResolve);

The event will always be called if the application would throw the exception

Could not load file or assembly 'Newtonsoft.Json, Version=9.0.0.1, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies. The system cannot find the file specified.

The event therefore catches the event and loads the correct dll:

Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    //This handler is called only when the common language runtime tries to bind to the assembly and fails.

    //Retrieve the list of referenced assemblies in an array of AssemblyName.
    Assembly MyAssembly, objExecutingAssemblies;
    string strTempAssmbPath = "";

    objExecutingAssemblies = Assembly.GetExecutingAssembly();
    AssemblyName[] arrReferencedAssmbNames = objExecutingAssemblies.GetReferencedAssemblies();

    //Loop through the array of referenced assembly names.
    foreach (AssemblyName strAssmbName in arrReferencedAssmbNames)
    {
        //Check for the assembly names that have raised the "AssemblyResolve" event.
        if (strAssmbName.FullName.Substring(0, strAssmbName.FullName.IndexOf(",")) == args.Name.Substring(0, args.Name.IndexOf(",")))
        {
            //Build the path of the assembly from where it has to be loaded.
            //The following line is probably the only line of code in this method you may need to modify:
            strTempAssmbPath = "C:\\Program Files\\PATH TO YOUR FOLDER" + "\\Newtonsoft.Json\\9.0.1";
            if (!strTempAssmbPath.EndsWith("\\")) strTempAssmbPath += "\\";
            //strTempAssmbPath += args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll";
            strTempAssmbPath += strAssmbName.Name + ".dll";
            break;
        }

    }
    //Load the assembly from the specified path.
    MyAssembly = Assembly.LoadFrom(strTempAssmbPath);

    //Return the loaded assembly.
    return MyAssembly;
}

Credits: https://www.chilkatsoft.com/p/p_502.asp

Rudi
  • 926
  • 2
  • 19
  • 38