Avoid using Assembly.LoadFrom

On MSDN, there’s a warning that using Assembly.LoadFrom() has disadvantages. The following could be a good illustration of the problems that may arise.

Not long ago I had a customer who was using Assembly.LoadFrom() to load types into their web service on-demand. Intermittently, he received HTTP 500 errors on the client, which he tracked back to a strange exception thrown in the service:

System.InvalidCastException: [A]<type A> cannot be cast to [B]<type A>. Type A originates from <assembly A> in the context 'LoadNeither' at location <location A>. Type A originates from <assembly A> in the context 'Default' at location <location B>.

As if a given type was not castable to itself. I hope you noticed that the types described above do differ in their load contexts and their containing assembly’s location. This helps investigating such issues, thanks to the improved error message.

Indeed, the problem was that my customer placed his plug-in assemblies into the Bin directory, and therefore these assemblies got copied to the temporary folder that ASP.NET uses to compile the web application (or web service for that matter). This directory happens to be the private path for the application domain the web service is running in. This means that every assembly on this path can be loaded via Assembly.Load().
Since client requests contained types from the plug-in assemblies, at some point, XmlSerializer tried de-serialize the XML. However, XmlSerializer is always using Assembly.Load() to load the required assembly into the default loading context. But types that customer was using in his code got loaded into a different context (LoadNeither in this case). As Suzanne Cook’s excellent post explains, types loaded into different context are never castable to each other.

Needless to say that this problem is not specific to web services or XmlSerializer. I’ve seen it also with .NET Remoting and the binary formatter, and very likely it can appear with other combinations of distributed frameworks and serializers.