Wednesday, June 03, 2009

Force Assembly To Use Another Version Of Library In .NET

It is known that signed assemblies in .NET can reference only other sugned assemblies. And moreover they reference specific version of assembly. This could lead to problems such as I encountered while working with NHibernate: for lazy loading it uses Castle.Core.dll of version 1.0.3, and my application also uses Castle.Windsor, which requires the same dll but of version 1.1.0. As a result application failed because it wans't able to find an assembly of correct version: there could be only one file with name Castle.Core.dll in a directory! I've tried to use private probing paths which reference directories with required versions of library, but this didn't helped me (or I was doing something wrong). All in all I found three solutions for this problem:
  1. Add all required version of referenced assembly to the GAC. So application will load proper versions of assemblies. This solution has two main drawbacks: firstly, adding assemblies to GAC requires administrator privilegies on system, which could be a blocker for some cases, especially for portable apps. Secondly, application will load two assemblies so it will use more resources and moreover similiar static types will exist in two instances and this could be a big problem if they allocate a lot of resources. However this solution iw great if two version of assembly are backword uncompatibile.
  2. Download source code of projects and recompile them with configuration I need. However this includes additional work to compile files which isn't as easy as it wants and moreover this situation can happen with closed source applications, so while sometimes this could be an good solutions in some cases this is just impossible.
  3. You can tell .NET runtime to use specific version of assembly instead of referenced in manifest. This is done by this code in *.config file
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<!-- NHibernate dynamic proxy wants Castle.Core version 1.0.3, but Windsor uses 1.1.0-->
<assemblyIdentity name="Castle.Core" publicKeyToken="407dd0808d44fbdc"/>
<bindingRedirect oldVersion="1.0.3.0" newVersion="1.1.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

Of coures this solution requires that new version is backward compatibile with older version. But this solution is much more simlier in deployment and there is no risk of having duplicates of "heavy" static resources. And what is more this allows to force usage of new version of assembly without any recompiling.