Redirecting Assemblies in .NET for MVC 3
Redirecting Assembly Versions
If you've got an ASP.NET MVC 3 project that uses libraries that were compiled against an older version of ASP.NET MVC, you can tell them to reference MVC 3 instead by adding an assembly redirect using <bindingRedirect> in web.config:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
So, if you don't have the source code or the opportunity to rebuild your libraries with the MVC 3 assemblies, this'll make sure all references to MVC v1.0 or v2.0 are redirected to v3.0. In my case working on NBlog, this fixed some discrepancies for third-party components like Autofac.Integration.Web.Mvc.dll and DotNetOpenAuth.dll that were throwing exceptions, or just behaving strangely, because they were referencing older MVC versions.
Redirecting Assembly Names
This problem is a bit trickier. It came about when I added a project reference to SharpBox. SharpBox has a dependency on JSON.NET to the assembly name Newtonsoft.Json.Net40.dll, but my project already references JSON.NET by a different name, Newtonsoft.Json.dll. So predictably, when I run the app, SharpBox can't find its JSON.NET dependency under the existing name:
Could not load file or assembly 'Newtonsoft.Json.Net40'
However, if I add a reference to both assemblies, the C# compiler throws error CS0433 because both assemblies contain the same namespaces and types, which produces ambiguity.
The type 'Newtonsoft.Json.JsonConvert' exists in both 'Newtonsoft.Json.dll' and 'Newtonsoft.Json.Net40.dll'
There are a few possible solutions. I could grab the source code for SharpBox and rebuild it against Newtonsoft.Json.dll, but I don't want to have to do that for every new SharpBox release. Ideally, I wanted a way to automatically resolve Newtonsoft.Json.Net40 to Newtonsoft.Json.
Using the <codeBase> hint
My first idea was to try an approach similar to the assembly version redirect above. But, instead of using a <bindingRedirect> I used a <codeBase> hint to try mapping Newtonsoft.Json.Net20.dll to the existing Newtonsoft.Json.dll assembly:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity
name="Newtonsoft.Json.Net20"
version="3.5.0.0"
culture="neutral"
publicKeyToken="30ad4fe6b2a6aeed" />
<codeBase version="3.5.0.0" href="bin\Newtonsoft.Json.dll"/>
</dependentAssembly>
</runtime>
</assemblyBinding>
Unfortunately however, this doesn't work. Using the Assembly Binding Log Viewer (fuslogvw.exe), it's possible to catch the binding error and view the details:

LOG: Attempting download of new URL file:///C:/Project/bin/Newtonsoft.Json.dll. LOG: Download was successful. Attempting setup of file: C:\Project\bin\Newtonsoft.Json.dll LOG: Entering download cache setup phase. LOG: Name is: Newtonsoft.Json, Version=3.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed WRN: Comparing the assembly name resulted in the mismatch: NAME ERR: The assembly reference did not match the assembly definition found. ERR: Setup failed with hr = 0x80131040. ERR: Failed to complete setup of assembly (hr = 0x80131040). Probing terminated.
As you can see, because the assembly names don't match the binding fails.
Handling AppDomain.AssemblyResolve Event
The .NET runtime goes through several steps to resolve an assembly reference, but even when it fails it still gives you a final chance to provide the assembly manually by firing the AppDomain.AssemblyResolve event. The required assembly name is passed in ResolveEventArgs.Name, so if it looks like the CLR is trying to load an assembly matching Newtonsoft.Json.*, we can return the already loaded JSON.NET assembly:
protected void Application_Start()
{
AppDomain.CurrentDomain.AssemblyResolve +=
(s, ea) => ea.Name.StartsWith("Newtonsoft.Json") ?
Assembly.GetAssembly(typeof(Newtonsoft.Json.JsonConvert)) : null;
}
This is a bit of a hack, but it works fine.
Loading both at runtime
The other approach is to just have the CLR load both assemblies. Just because the C# compiler won't let us reference both Newtonsoft.Json.dll and Newtonsoft.Json.Net40.dll, it doesn't mean you can't have both assemblies loaded at runtime.
Any second-tier dependencies like Newtonsoft.Json.Net40.dll are resolved by MSBuild at build time, so long as they're in the same folder as the assembly that uses them. In this case, they're copied along with everything else into the /bin folder and loaded at runtime.
If, however, these dependencies are in a different folder then you can either copy them manually using a post-build event:

Or, add that folder to your probing path so the CLR knows where to look for it:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="Lib"/>
</assemblyBinding>
</runtime>