I've been tasked in creating a new module for an application, and so, I'm adding new DLLs to the project. This is all fine and well.
However, in my DLLs I'd like to use a new version of an external DLL (over which I have no control). If I just reference the new DLL and work with that one only, my code will work, but the old code will stop functioning.
Could not load file or assembly 'itextsharp, Version=5.0.6.0, Culture=neutral, PublicKeyToken=8354ae6d2174ddca' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
I've tried a simple trick of changing the DLLs name, but that apparently was a bit too naive of me, to think it would work. I've tried using the external aliases (by defining them in my references), but I still don't know how to get two files with the same name into one BIN folder...
What should I do?
It's possible. You could install the DLL in the GAC (requires strong named assemblies) in order for both applications to have easy access to it. Or stick it in a folder and have both apps search that folder for the dll.
For a file that is missing version info completely: After opening the DLL in Visual Studio, go to Edit > Add Resource > Version and click New. Then in the new Version tab, change FILEVERSION and PRODUCTVERSION, CompanyName, etc. Save the files and you're all set!
Because the strong-named assembly's version number is part of its identity, the runtime can store multiple versions of the same assembly in the global assembly cache and load those assemblies at run time.
You can certainly embed another DLL as a resource and extract and load it at runtime if that's what you need.
Let's assume you have a project structure as follows:
...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(""); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With