Friday, 31 March 2006

"Cannot find the assembly" for Binary Deserialization

I have an ASP.NET search tool which stores a data structure in the Application cache. This 'problem' relates to the next version so stay tuned for the new code.

The structure is built up via a C# class which is defined in a .CS file. It takes a while to build (it crawls the web), so I don't want the build process to be running all the time.

The .CS file is compiled and executed 'on the fly' because it is only referenced in ASPX page @PAGE SRC=""

The assembly it is compiled into therefore has a random (and different) name every time the 'web application' restarts (eg. IIS is restarted, the computer is rebooted, or ever a change to web.config). The assembly name could be anything from "udlo.dll" to "9pd_.dll".

Rather than re-build the data structure every time the 'web application' restarts, I decided to serialize it to file, and look for the file to deserialize on restart, before rebuilding.

The XML serialized file is 77Mb+. Too big. The Binary serialized file is 4Mb. Better.

Imagine my frustration when - despite all the code looking right, the ASPX kept returning this error System.Runtime.Serialization.SerializationException: Cannot find the assembly ***
where *** was always a different, random dll name (because of the dynamic compilation of @PAGE SRC="" code files).

I already had an inkling that Binary-serialized objects could only be deserialized by the same assembly that serialized them, but I wasn't really sure why. Thankfully, goxman supplied some answers on CodeProject .NET XML and SOAP Serialization Samples, Tips.
Type information is also serialized while the class is serialized enabling the class to be deserialized using the type information. Type information consists of namespace, class name, assembly name, culture information, assembly version, and public key token. As long as your deserialized class and the class that is serialized reside in the same assembly it does not cause any problem. But if the serializer is in a separate assembly, .NET cannot find your class’ type hence cannot deserialize it...
In this case we can write our own class’s binder and tell the deserialization to use our binder while looking for our classes’ types.

As you can see - this is a real problem in my scenario - every time I need to deserialize my objects, it is because the application has restarted, the code is recompiled and by definition the assembly name is different!

Thankfully the CodeProject article goes on to demonstrate how to implement System.Runtime.Serialization.SerializationBinder and attach it to formatter.Binder... and everything worked!

No comments:

Post a Comment