Using multiple versions of the same DLL

Another viable option is to use extern, as described here:

http://blogs.msdn.com/b/abhinaba/archive/2005/11/30/498278.aspx


If the AppDomains solution isn't applicable in your case, you are under time pressure, have conflicting requirements (like that ever happens), and don't mind ridiculously contrived hacks:

  • Decompile the newer version of the assembly using the ildasm tool (part of the Developer Command Prompt included with Visual Studio)
  • Edit the generated .il file to find/replace the assembly namespace references. Using the cited example, this would be a change from itextsharp.X to itextsharp.new.X
  • Likewise, edit the value for the AssemblyTitleAttribute. This requires translating the ASCII characters to hex.
  • Recompile the .il file using ilasm
  • Note that this may need to be repeated for any dependent assemblies (e.g. - someassembly.core.whatever)
  • Add the new .dlls to your project with a different name and reference them explicitly (rather than via nuget or whatever)

Hey, don't look at me like that. I did say ridiculously contrived hack ...


Let's assume you have a project structure as follows:

Project Diagram

...where A and B are class libraries, and C is an executable-type project (such as a unit test or console project).

Let's assume the folder structure is like this:

ABC.sln
A/A.csproj
A/...
B/B.csproj
B/...
C/C.csproj
C/...
lib/thirdparty4/thirdparty.dll
lib/thirdparty5/thirdparty.dll

If we attempted to naively reference our projects together, we'd have a problem: two versions of thirdparty.dll will be copied into the same folder (the output (i.e., bin) directory of C). We need a way for C to copy both dlls into its output directory, and provide a mechanism for referencing either one.

To solve this, I modified C.csproj to contain the following:

<ItemGroup>
  <Content Include="..\lib\thirdparty4\thirdparty.dll">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    <Link>thirdparty4\thirdparty.dll</Link>
  </Content>
  <Content Include="..\lib\thirdparty5\thirdparty.dll">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    <Link>thirdparty5\thirdparty.dll</Link>
  </Content>
</ItemGroup>

This will instruct it to create both thirdparty4\thirdparty.dll and thirdparty5\thirdparty.dll in its output directory.

Now, after building C, its output directory looks like this:

C\bin\Debug\A.dll
C\bin\Debug\B.dll
C\bin\Debug\C.dll
C\bin\Debug\thirdparty4\thirdparty.dll
C\bin\Debug\thirdparty5\thirdparty.dll

To instruct C to use both of these dlls, I added an App.config file to it, with the following:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="thirdparty" culture="neutral" publicKeyToken="1234567890123445"/>
        <bindingRedirect oldVersion="4.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
        <codeBase version="4.0.0.0" href="thirdparty4\thirdparty.dll" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="thirdparty" culture="neutral" publicKeyToken="1234567890123445"/>
        <bindingRedirect oldVersion="5.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
        <codeBase version="5.0.0.0" href="thirdparty5\thirdparty.dll" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

This will instruct the assembly to, depending on which version is in need, use one DLL or the other, both of which will be available within subfolders of the output directory. (The bindingRedirect elements are optional, but you can use them if you need a range of revisions for this to apply to.)


You can load another version into a specific AppDomain

Possibly too detailed, but here is an article that demonstrates the use of AppDomains in a useful setting and how they work:

http://msdn.microsoft.com/en-us/magazine/cc164072.aspx

In a very basic sense it comes down to this sample code:

    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
    ...

    static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        if (/*some condition*/)
            return Assembly.LoadFrom("DifferentDllFolder\\differentVersion.dll");
        else
            return Assembly.LoadFrom("");
    }