4

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.

Rick Minerich
  • 3,078
  • 19
  • 29
  • A quick note: Due to the nature of my particular case, I can't use any type of serialization external to .NET 2.0 or lower. – Rick Minerich Apr 05 '10 at 16:06
  • Using `` in the app.config file ought to be safer and requires no code. – Hans Passant Apr 05 '10 at 16:14
  • This is to be used in a widely distributed library and so can't be controlled by the app.config. – Rick Minerich Apr 05 '10 at 16:56
  • Metadata-based serialization (`BinaryFormatter` etc). Sigh. How often do I see this biting people and biting *hard*. I hate to say it (and it sounds like it is too late to be useful), but **don't do that**. Use contract-based serialization. There are plenty. – Marc Gravell Apr 05 '10 at 20:18
  • Not an option unless I want to write it from scratch. – Rick Minerich Apr 06 '10 at 13:21

3 Answers3

2

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.

TarkaDaal
  • 18,798
  • 7
  • 34
  • 51
  • 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 Apr 05 '10 at 17:01
0

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

TarkaDaal
  • 18,798
  • 7
  • 34
  • 51
  • 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 Apr 05 '10 at 16:31
0

This should answer your question: SerializationBinder with List<T>

When using generic types in the SerializationBinder.BindToType, you need to use weak type names instead of fully qualified type names.

Community
  • 1
  • 1
tbergelt
  • 2,196
  • 1
  • 14
  • 5