Yesterday, I was presented with the following error message while running an application that I created:
The located assembly's manifest definition with name 'XXX' does not match the assembly reference.
The .NET Framework (specifically Fusion) is throwing a FileLoadException. This particular exception is occuring because .NET is attempting to load and bind to a particular version of a library at runtime. Now I know what precipitated this particular error: I had just upped the version # of the application. The symptoms were apparent, but the remedy wasn't quite obvious at first - at least until I figured out what was truly going on.
I had changed the version of my application (and all dependencies across the board) from version 1.0.0.0 to 2.0.0.0. This would, under normal circumstances be sufficient to avoid this particular error, however these weren't normal circumstances. Unfortunately, this particular exception didn't really identify the root of the problem, so I had to dig a bit deeper.
Here's what I did to try to fix the problem:
- I opened up an administrative console and ran fuslogvw.exe (a handy tool available with the .NET Framework SDK). This particular tool is great for helping diagnose assembly binding errors.
- Selected the 'Log Failures' checkbox (this in turn updated HKLM\SOFTWARE\Microsoft\Fusion\LogFailures to 0x00000001).
- Selected the 'Custom' radio control.
- Ran REGEDIT adding a string value to HLKM\SOFTWARE\Microsoft\Fusion\LogPath, setting its value to c:\fusionlogs (a folder I created for the purpose of capturing the logs).
- Ran IISRESET (my issue was, in fact, occurring within an ASP.NET application, and I had to restart the aspnet_wp.exe process for the FUSLOGVW and registry updates to take effect).
- Reran the ASP.NET application to recreate the error.
With logging in effect, I simply had to refresh the FUSLOGVW dialog and see the exception log appear.
A quick glance in the log indicated that it could not load version 1.0.0.0 of my application. What!? Why is it even trying to load the old version? This shouldn't be happening! In most normal circumstances, like I said, this wouldn't be an issue. But it turns out that my application actually has two parts:
- The web application (the one manifesting the problem).
- An administrative / management console that was installed via MSI on my machine in the \Program Files folder. This console has the same dependencies as my web application. The role of the console is to aggregate data that has been tested and verified and 'publish' them to a 'production' database for the web application to consume. Some of the published data (in the form of XML) contains fully-qualified references to a third-party toolset used to publish the XML so that it can be read back dynamically by the component.
Well, despite having compiled the web application successfully, I had legacy (v1.0.0.0) dlls in the \Program Files directory, so when the data got published it would bake a v1.0.0.0 stamp in the XML file. At runtime, the ASP.NEt application would try to load the v1.0.0.0 dll when only a v2.0.0.0 dll exists.
Once I saw that this was the problem, it was easy to fix. The .NET Framework supports a mechanism known as binding redirection which effectively allow you to use a dll of a different version that what was originally bound at compile time. Therefore, if an assembly were compiled against a strongly-named v1.0.0.0 assembly you can effectively redirect it to use v2.0.0.0 at runtime (note that this really only applies to strongly-named assemblies as there is no version checking for assemblies without strong names - the newer version will be used by default). In order to accomplish this, you need to establish a .config file with a section that resembles the following:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="FancySchmancyLibrary" publicKeyToken="caeeebc55fa1f62d" culture="neutral" />
<bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
I've seen some people try to set oldVersion to something resembling "1.0.*" but that syntax is not supported. If you want to redirect all 1.0.x.x versions, you must specify a range such as:
<bindingRedirect oldVersion="1.0.0.0-1.0.99999.99999" newVersion=“2.0.0.0“ />
It's a pretty powerful concept and in this particular case it saved my hide.