SerializationBinder with List<T>

dan picture dan · Apr 26, 2011 · Viewed 7.9k times · Source

I'm trying to make the BinaryFormatter work across different versions of my assembly. The actual class I want to deserialize to is exactly the same in each assembly version, but on deserialization, because the objects are serialized include the assembly name they came from, the BinaryFormatter is complaining that it can't find the right assembly. So I created a custom SerializationBinder that tells the BinaryFormatter to always deserialize to the current assembly version.

My scheme works and can deserialize objects correctly, but it doesn't work if my object is a List of T, where T was a type serialized from an older version of my assembly.

Is there some way to make this work with Lists and other generic types where the type parameter is a class from my assembly?

//the object i want to deserialize
class MyObject
{
     public string Name{get;set;}
}

//my binder class
class MyBinder : SerializationBinder
{
    static string assemblyToUse = typeof (MyObject).Assembly.FullName;
    public override Type BindToType(string assemblyName, string typeName)
    {
        var isMyAssembly = assemblyName.StartsWith("oldAssemblyName");
        var assemblyNameToUse = isMyAssembly ? assemblyToUse : assemblyName;
        var tn = typeName + ", " + assemblyNameToUse;
        return Type.GetType(tn);            
    }
}


//my deserialize method
static object BinaryDeserialize(string input)
{
    var arr = Convert.FromBase64String(input);
    var ms = new MemoryStream(arr);
    ms.Seek(0, SeekOrigin.Begin);
    var bf = new BinaryFormatter();
    bf.Binder = new MyBinder();
    var obj = bf.Deserialize(ms);

    return obj;
}

static void Test()
{
    //this works
    //serialized(new MyObject());
    var str = ReadSerialized_MyObject();  
    var obj = BinaryDeserialize(str);

    //this doesn't work
    //serialized(new List<MyObject>());
    var str2 = ReadSerialized_List_of_MyObject(); 
    var obj = BinaryDeserialize(str2);
}

Answer

tbergelt picture tbergelt · Nov 4, 2011

If you serialized an instance of List< MyClass > from your version 1.0.0.0 assembly, the SerializationBinder.BindToType function will be asked to provide this type:

System.Collections.Generic.List`1[[MyAssembly.MyClass, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=12345678901234567890]]

In order to remap the List< MyClass > type to your version 2.0.0.0 assembly, you need to change the type name to this:

System.Collections.Generic.List`1[[MyAssembly.MyClass, MyAssembly]]

The main point to note, is that the assembly name is not fully qualified. If you try to fully qualify the assembly name with a 2.0.0.0 version number, it will not work.