Deserializing data into a dynamically loaded Assembly

What does scripting languages like php, Perl, python offer over compiled languages? Well if you ask me i would say the ease of development. Make a change in the code and then see the change reflected quickly. This is one of the main reason why scripting is preferred in the web environment. Majority of the websites these days are powered by php in the LAMP stack. Performance of scripted language is far lower than any compiled binary. Compare that with the ASP.NET. The scripts are compiled into MSIL and run on the .NET runtime. Even without caching the ASP framework is almost 2-3 times faster than the Apache on php with mysql. I am not a MS fan-boy nor an open source evangelist.  I had the privilege on doing extensive development on both platforms. There are times when i wished for a platform which had the best of both worlds. When php scores on flexibility for advanced developers. ASP.NET scores on its default ability to separate UI from Logic. Enough of this Web programming. Let me get into what i started out to do.

I had been working on a .NET project where  a DLL A.dll is being used by two different applications. On one application i create an object of a class C inside A.dll, fill its members and serialize it into a binary stream using the standard .NET serializer  and save it into a file. On the second application when i get a request to load the data from the file, I dynamically load the Assembly A.dll. Then i open the file that i saved the byte dump then deserialized it back into an object of the class. Sounds easy, Not so… I was getting an Exception.
System.Runtime.Serialization.SerializationException: Unable to find assembly ‘A’. 

Then i compiled the dll with the application and checked whether its working.  I then got another exception while casting the Deserialized object into a variable of type A.C

Unable to cast type A.C into A.C. 

What the hell!!!  That was my first impression. This was one of the least helpful messages the Visual Studio debugger threw at me. I then tried searching for related resources online in vain.  That’s when i came across this elegant solution involving AppDomains and Serialization Binders. Needless to say my deserialization worked on the dynamically loaded assembly. You can find more details about creating AppDomains here.

I am attaching my C# code below. Hope this proves helpful to you. Look at the serialization binder class in the Deserialize function. The binder class allows you to change the type to which you want to deserialize the byte array to.


public static byte[] Serialize(Object o){           
MemoryStream stream = new MemoryStream(); BinaryFormatter formatter = new BinaryFormatter(); formatter.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple; formatter.Serialize(stream, o); return stream.ToArray(); }
public static Object BinaryDeSerialize(byte[] bytes){ MemoryStream stream = new MemoryStream(bytes); BinaryFormatter formatter = new BinaryFormatter(); formatter.AssemblyFormat
= System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple; formatter.Binder
= new VersionConfigToNamespaceAssemblyObjectBinder(); Object obj = (Object)formatter.Deserialize(stream); return obj; }
internal sealed class VersionConfigToNamespaceAssemblyObjectBinder : SerializationBinder { public override Type BindToType(string assemblyName, string typeName) { Type typeToDeserialize = null; try{ string ToAssemblyName = assemblyName.Split(',')[0]; Assembly[] Assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly ass in Assemblies){ if (ass.FullName.Split(',')[0] == ToAssemblyName){ typeToDeserialize = ass.GetType(typeName); break; } } } catch (System.Exception exception){ throw exception; } return typeToDeserialize; } }

19 responses to this post.

  1. Posted by ActiveEngine Sensei on December 23, 2007 at 4:02 pm

    CLSA.Net has a nice DataPortal concept that allows you to copy objects via Web Services, remoting, and the MS Enterprise Services. The solution is similar to what you have worked out here.

    Here’s a link to his site:

    http://www.lhotka.net

    Reply

  2. Posted by ActiveEngine Sensei on December 23, 2007 at 4:04 pm

    On a different note, TheCodeslinger has two posts related to Dynamic instantiation of objects that you might find interesting. I posted these two links on my blog:

    New Blood in Deadwood

    Enjoy!

    Reply

  3. Simply brilliant!

    Reply

  4. Excellent approach, Thanks.

    But the DeSerialization fails if Generic Types are used. I posted some changes to the code that makes it work for Generic Types.

    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2816458&SiteID=1&mode=1

    Reply

  5. Posted by Alexandre on March 13, 2008 at 6:04 pm

    This is great, very useful, exactly what I was looking for.

    Reply

  6. Posted by Alan Balkany on June 2, 2008 at 3:43 pm

    Wow, it worked! For three days I’ve been struggling to deserialize from a managed DLL. I kept getting the error “Parse Error, no assembly associated with Xml key”. Thanks!

    Substituting your code for the SoapFormatter worked the first time. I’ve rearranged the code slightly to use any Stream:

    public static void serialize(Object o, Stream stream)
    {
    //MemoryStream stream = new MemoryStream();
    BinaryFormatter formatter = new BinaryFormatter();
    formatter.AssemblyFormat
    = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
    formatter.Serialize(stream, o);
    //return stream.ToArray();
    }

    public static Object binaryDeserialize(Stream stream)
    {
    //MemoryStream stream = new MemoryStream(bytes);
    BinaryFormatter formatter = new BinaryFormatter();
    formatter.AssemblyFormat
    = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
    formatter.Binder
    = new versionConfigToNamespaceAssemblyObjectBinder();
    Object obj = (Object)formatter.Deserialize(stream);
    return obj;
    }

    internal sealed class versionConfigToNamespaceAssemblyObjectBinder : SerializationBinder
    {
    public override Type BindToType(string assemblyName, string typeName)
    {
    Type typeToDeserialize = null;
    try
    {
    string ToAssemblyName = assemblyName.Split(‘,’)[0];
    Assembly[] Assemblies = AppDomain.CurrentDomain.GetAssemblies();
    foreach (Assembly ass in Assemblies)
    {
    if (ass.FullName.Split(‘,’)[0] == ToAssemblyName)
    {
    typeToDeserialize = ass.GetType(typeName);
    break;
    }
    }
    }

    catch (System.Exception exception)
    {
    throw exception;
    }
    return typeToDeserialize;
    }
    }

    Reply

  7. Posted by Adrian Uifalean on November 19, 2008 at 1:22 pm

    Thank’s a lot; i have the same situation and this messege “Unable to find assembly …” it drives me insane; the solution with SerializationBinder works fine;

    Reply

  8. Posted by Pearl on April 24, 2009 at 11:09 am

    Thankyou very much ………….
    APpreciated your solution it works fine;
    Kind of you!!!!

    Cheeeers

    Reply

  9. Posted by Carsten Lund Jørgensen on May 31, 2009 at 9:02 pm

    Thank you so very very much.

    I had the exact same problem, and your solution just worked perfectly. You just saved my day 🙂

    Reply

  10. Posted by Jamie on August 4, 2010 at 6:53 am

    Well that is a stupid problem to have which just wasted half my day.

    This works great!

    Thanks heaps

    Reply

  11. Posted by Haribabu on November 10, 2010 at 3:40 pm

    Hi All,We are facing the same issue with SSRS, and we are not using any web references , we are getting the error like “Unable to find assembly App_Web_[PageName].[Hash]”.

    I saw the above solutions but didn’t get where to add all those code lines..

    Please help us in solving this BIG BIG Issue.

    Thanks,
    Haribabu K.

    Reply

  12. Thanks so much for this… I was using custom deserialization to allow for deserialization into a List and trying to do it through dynamically loaded assemblies. This obscure issue was driving me crazy, and this article solved my issue.

    Reply

  13. Posted by zmatt on April 19, 2011 at 8:26 am

    Thanks you very much !!

    It works 😀

    Reply

  14. Excellent information and was exactly what I was looking for. Also thank you to @Mohit for the information on Generics. Putting all of this together as solved a major problem for me.

    Reply

  15. Posted by Luisa on September 12, 2011 at 1:47 pm

    Thank you! you made my day

    Reply

  16. Posted by Bobby on February 3, 2012 at 6:00 pm

    It works fine on one run, but fails on the second run. I am creating a class at run time and serializing it in cache and later I am de-serializing the object after getting it from cache in every run. Any one know whay?

    Reply

  17. Posted by Anish on February 18, 2014 at 5:05 pm

    Was struggling with this for a couple of days before I even realized what my problem was. With your code, in my projects (with some minor modifications) it seems to work in initial testing. Thank you so much for posting the code!

    Reply

  18. I read many posts for this issue but your solution is the best approach I’ve found

    Reply

Leave a comment