Could NOT LOad file or assembly - Part 1

The error message "Could not load file or assembly" can be quite a common error in ASP.NET applications. This is because it can occur for a whole plethora of reasons and this in itself can make it a bit of a tricky problem to solve.

Of course in some cases it could be competely trivial - you just forgot to deploy one of the assemblies that your application depends on to the BIN folder on your production server, that kind of thing.

However sometimes the cause is less obvious.

So what does the error look like in full? You would probably see something more akin to this:

System.IO.FileNotFoundException: Could not load file or assembly 'MyLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0e1d67af9d31f077' or one of its dependencies. The system cannot find the file specified.
File name: 'MyLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0e1d67af9d31f077' ---> System.IO.FileNotFoundException: Could not load file or assembly 'MyLibrary' or one of its dependencies. The system cannot find the file specified.
File name: 'MyLibrary'

 

This might occur when you are explicitly trying to load an assembly (for example by calling Assembly.Load) or more likely it occurs indirectly as a result of something else your application does, like trying to display a particular web control for example.

 

Now there are some known problems that can lead you to get this error and here are a few examples:

 

915782 FIX: You may receive an InvalidCastException error in an ASP.NET-connected Web application
support.microsoft.com/default.aspx?scid=kb;EN-US;915782

919825 You may receive an error message that is misleading when you generate a delay-signed ActiveX wrapper in a Visual C# Windows application project in Visual Studio 2005
support.microsoft.com/default.aspx?scid=kb;EN-US;919825

820126 BUG: New Interop DLL Is Not Put in the Correct Location for the Project When a COM Component Is Added
support.microsoft.com/default.aspx?scid=kb;EN-US;820126

823196 PRB: You Receive a "System.IO.FileNotFoundException" Error When the Client Application Calls a Web Service
support.microsoft.com/default.aspx?scid=kb;EN-US;823196

 

As you can see there is quite a variety of situations and causes for this and similar errors. Some of the situations are pretty specific.

Some tools that can be helpful in diagnosing the cause of such failures are FUSLOGVW.EXE (that comes with the Microsoft .NET SDK) and also the trusty old favourite FileMon.

 

The other day I was assisting a customer with a situation where an ASP.NET 1.1 application that had worked perfectly well for quite some time gave a "file not found" error when configured to run with ASP.NET 2.0.  After examining the application and its configuration files and discussing the problem with her I constructed a small sample application (outside of ASP.NET) to focus on the application's use of bindingRedirect.

I compiled the EXE along with two versions of MyLibrary.dll using Visual Studio .NET 2003 and ran the application using this configuration file:

<configuration>
<startup>
<requiredRuntime version="v1.1.4322" safemode="true"/>
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<qualifyAssembly partialName="MyLibrary" fullName="MyLibrary,version=1.0.0.0,publicKeyToken=0e1d67af9d31f077,culture=neutral" />
<dependentAssembly>
<assemblyIdentity name="MyLibrary" publicKeyToken="0e1d67af9d31f077" culture="neutral" />
<bindingRedirect oldVersion="1.0.0.0-1.0.0.0" newVersion="1.0.0.1" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

All the EXE did was to do Assembly.Load("MyLibrary") and display the version of MyLibrary. With this configuration file it should realise that when trying to load version 1.0.0.0 of MyLibrary.dll, the version the EXE was referencing at compilation time, the loader should instead load version 1.0.0.1.

This worked and told me that version 1.0.0.1 of MyLibrary had been loaded.

I then changed

<requiredRuntime version="v1.1.4322" safemode="true"/>

to

<requiredRuntime version="v2.0.50727" safemode="true"/>

so that the 2.0 runtime would be used and ran the application again.

This also worked and told me that version 1.0.0.1 of MyLibrary had been loaded.

Hmm. This was not the errant behaviour the customer was reporting.

So I sent my sample application to the customer and she duly spotted that the syntax of the oldVersion attribute that I was using was subtly different to what she had.

The key point was that I had

<bindingRedirect oldVersion="1.0.0.0-1.0.0.0" newVersion="1.0.0.1" />

whereas she had something more like

<bindingRedirect oldVersion="1.0-1.1" newVersion="1.0.0.1" />

So I changed mine to say

<bindingRedirect oldVersion="1.0-1.1" newVersion="1.0.0.1" />

and

<requiredRuntime version="v1.1.4322" safemode="true"/>

and it still worked.

I then changed it to use the 2.0 runtime:

<requiredRuntime version="v2.0.50727" safemode="true"/>

Sure enough, it now failed.

A bit of digging showed that all our documentation for the syntax of version numbers in attributes like oldVersion is that they should include four parts and that each part can either be a number or a number range.  We don't say the two digit syntax is valid though neither do we say it is invalid. Mind you it would be hard to document everything that is not valid. Usually you find out because something does not work. In this case it just works. The load in 2.0 just ignores the oldVersion attribute and so goes ahead and looks for version 1.0.0.0 of MyLibrary.dll that the EXE was compiled against. So if the old assembly is not available you get the dreaded  "System.IO.FileNotFoundException - Could not load file or assembly.."

From asking around internally it seems this was unintentional that it could work that way in 1.1, which in turn led to an unintentional breaking change when migrating applications to 2.0 for anyone that had come to rely on the old syntax. Fortunately in this case the fix was just an easy edit in Notepad.

 

Here are the docs for the bindingRedirect element.

 

Bye for now

 

Doug