views:

127

answers:

2

In other cases it has been suggested that you simply add a SerializationBinder which removes the version from the assembly type. However, when using generic collections of a type found in a signed assembly, that type is strictly versioned based on its assembly.

Here is what I've found works.

internal class WeaklyNamedAppDomainAssemblyBinder : SerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName)
    {
        ResolveEventHandler handler = new ResolveEventHandler(CurrentDomain_AssemblyResolve);
        AppDomain.CurrentDomain.AssemblyResolve += handler;

        Type returnedType;
        try
        {
            AssemblyName asmName = new AssemblyName(assemblyName);
            var assembly = Assembly.Load(asmName);
            returnedType = assembly.GetType(typeName);
        }
        catch
        {
            returnedType = null;
        }
        finally
        {
            AppDomain.CurrentDomain.AssemblyResolve -= handler;
        }

        return returnedType;
    }

    Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        string truncatedAssemblyName = args.Name.Split(',')[0];
        Assembly assembly = Assembly.Load(truncatedAssemblyName);
        return assembly;
    }
}

However, causing the binding process to change globally seems rather dangerous to me. Strange things could happen if serialization was happening in multiple threads. Perhaps a better solution is to do some regex manipulation of the typeName?

Edit: The string based method does not work. Generics apparently need a full strongly named type. Quite heinous if you ask me.

A: 

Rather than serializing the whole collection, could you iterate through it and serialize each element individually? Then you can use the SerilizationBinder approach.

Dan
However, in this case there is the added maintenance overhead of ensuring new fields are serialized. I've been trying to avoid manually implementing ISerializable. I already have automatic backwards compatibility testing.
Rick Minerich
+1  A: 

The AssemblyResolve event is only fired if regular binding fails. So, anything that can be resolved through normal methods will be. Only deserialization operations are likely to fire the event, and you've got a perfectly valid strategy for trying to resolve those.

I'd add the AssemblyResolve event handler when the program starts up and leave it there, rather than adding and removing it. That removes a potential source of multi-threading issues.

Dan
Event removal isn't thread safe? In that case, perhaps I should add a guard to my AssemblyResolve to ensure it is only used for this assembly.
Rick Minerich