C# – BinaryFormatter.Deserialize is “Unable to find assembly”

While testing a SQL CLR procedure recently I came across an issue with the binary formatter deserialization failing because it could not find the assembly for the type (even though the type is within the same assembly as the deserialization code).

The database application I have been working on has an initial request object (from a web service or web site) that is serialized using the binary formatter and stored in a Request table. It is then added into a Queue to be processed by one or more Service Broker services at a later time.

The serialization and deserialization of the request object is performed by a SQL CLR procedure, utilising the “System.Runtime.Serialization.Formatters.Binary.BinaryFormatter” formatter.

While testing that the Service Broker was configured correctly I was reusing the same Request table data, where the request object had previously been serialized and saved to the table. However I quickly noticed that after re-deploying the SQL CLR project I was running into an error while deserializing the object (note: the type being serialized/deserialized is in the same assembly as the code that serializes it):

Unable to find assembly 'MyAssembly; Version=1.0.3463.18923;
Culture=neutral; PublicKeyToken=40e3171cc8066fe6'.

After a little googling it became apparent that the binary formatter stores the type information within the serialized object so that it knows what type to deserialize it to (that makes sense), however this becomes a big issue if you are storing data for periods of time and need to maintain backwards compatibility with new versions of the assembly containing the type information.

Luckily the guys at MS had thought of this and provided us with the “System.Runtime.Serialization.SerializationBinder” class. By inheriting from this class it is possible to redirect all the requests for types from the binary formatter to the types of your choice.

Here is a sample that will allow the types to be found in the current assembly regardless of which version of the assembly originally created the serialized stream:

        sealed class AllowAllAssemblyVersionsDeserializationBinder : System.Runtime.Serialization.SerializationBinder
        {
            public override Type BindToType(string assemblyName, string typeName)
            {
                Type typeToDeserialize = null;

                String currentAssembly = Assembly.GetExecutingAssembly().FullName;

                // In this case we are always using the current assembly
                assemblyName = currentAssembly;

                // Get the type using the typeName and assemblyName
                typeToDeserialize = Type.GetType(String.Format("{0}, {1}",
                    typeName, assemblyName));

                return typeToDeserialize;
            }
        }

        public static MyRequestObject Deserialize(byte[] b)
        {
            MyRequestObject mro = null;
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            System.IO.MemoryStream ms = new System.IO.MemoryStream(b);

            // To prevent errors serializing between version number differences (e.g. Version 1 serializes, and Version 2 deserializes)
            formatter.Binder = new AllowAllAssemblyVersionsDeserializationBinder();

            // Allow the exceptions to bubble up
            // System.ArgumentNullException
            // System.Runtime.Serialization.SerializationException
            // System.Security.SecurityException
            mro = (MyRequestObject)formatter.Deserialize(ms);
            ms.Close();
            return mro;
        }

In my case the type itself had not changed between assembly versions, only the assembly version information. However the MSDN link below shows an example of allowing backwards compatibility between different versions of the type where the type itself may have changed significantly.

(http://msdn.microsoft.com/en-us/library/system.runtime.serialization.serializationbinder(VS.71).aspx)

P.S. this would also be a great solution if you are attempting to deserialize an object that was created in a different assembly that you cannot reference in your own project for some reason – providing you know the structure of the object and create a similar class in your own assembly.

27 thoughts on “C# – BinaryFormatter.Deserialize is “Unable to find assembly””

  1. very helpful. I think there’s a typo:

    AllowAllAssemblyVersionsDeserializationBinder

    doesn’t match

    formatter.Binder = new AllowAllVersionDeserializationBinder();

    But my problem is fixed, thanks much!

  2. actually this reason can be avoided by generating a dll library for the common DTO object from another VS project and adding the built dll file as a reference to both serialization and deserialization classes!

  3. Thanks, bro … it worked!, uff!!!

    using System.Reflection;

    public sealed class MessageSerializers : System.Runtime.Serialization.SerializationBinder
    {

    ….
    public override Type BindToType(string assemblyName, string typeName)
    { … as you said …
    }

    public static IMessage DeserializeMessage(byte[] bMessage)
    {

    formatter.Binder = new MessageSerializers();
    Object message = formatter.Deserialize(ms);
    return (IMessage)message;
    }

    Very helpful! Thanks!

  4. Thanks a lot. Helped me out of a really tough situation.. A minor variation of this by just using the typename worked in my case..

    1. Hi earlslick,

      Play around with line 10, debug it and check what the deserializer passes in as “assemblyName”. You will need to change it to the appropriate value for the assembly that contains the type you intend to use as the deserialized type.

      Cheers,
      J

  5. Excellent, exactly what I needed, this saved me a LOT of trouble I was wondering what would be an alternative to this binary formatter because of this error. Thanks a ton!

    1. PS: my situation was that in the same assembly and by the same version as well, I don’t know why it didn’t work. But your class AllowAllAssemblyVersionsDeserializationBinder worked like magic.

  6. Awsome – having now to play with the XML seraliser… I am just starting to appreciate how powerful this is and (in my context) much more managable code.

  7. It’s fantastic. Thank you so much!!!! I was so desperate because I didn’t know how to solve this. But it finally works!!!

  8. This is a wonderful article, but unfortunately, it will never work with nested types. Try it and you’ll see what I mean.

    1. Put it where you are doing your deserialisation – most likely in your main application/form code, but could be anywhere you are experiencing the problem.

  9. this is for custom class which have list and non list object

    sealed class VersionDeserializationBinder : SerializationBinder
    {
    public override Type BindToType(string assemblyName, string typeName)
    {
    Type typeToDeserialize = null;
    string currentAssemblyInfo = Assembly.GetExecutingAssembly().FullName;

    //my modification
    string currentAssemblyName = currentAssemblyInfo.Split(‘,’)[0];
    if (assemblyName.StartsWith(currentAssemblyName))assemblyName = currentAssemblyInfo;

    typeToDeserialize = Type.GetType(string.Format(“{0}, {1}”, typeName, assemblyName));
    return typeToDeserialize;
    }

Leave a Reply