Question

I have a bunch of types which have been moved from one assembly to another. I am trying to deserialize data which was serialized using the old assembly into types in the new assembly by using a SerializationBinder.

EDIT: Root namespace of the assembly is same as the assembly name. The old assembly does not exist anymore.

sealed class TypeMapBinder : SerializationBinder
    {
        public override Type BindToType( string assemblyName, string typeName )
        {
            Type typeToDeserialize = null;

            if ( assemblyName.Contains( "old namespace" ) )
                typeToDeserialize = Type.GetType( typeName.Replace( "old namespace", "new namespace" ) );
            else
                typeToDeserialize = Type.GetType( String.Concat( typeName, ", ", assemblyName ) );

            return typeToDeserialize;
        }
    }

deserialization code looks something like this -

using ( MemoryStream ms = new MemoryStream( byteArr ) )             {
                BinaryFormatter formatter = new BinaryFormatter( );
                formatter.Binder = new TypeMapBinder( );
                return formatter.Deserialize( ms );             
}

When i try to deserialize i get an error where its trying to load the old assembly.

Could not load file or assembly 'old assembly' or one of its dependencies. The system cannot find the file specified.

Was it helpful?

Solution

I think I'm seeing the same problem.

The BindToType method of my SerializationBinder does not emit any type, which refers to the old assembly, but still, the BinaryFormatter tries to load that old assembly:

System.IO.FileNotFoundException : Could not load file or assembly 'Old.Interfaces, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
   at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, ref StackCrawlMark stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, ref StackCrawlMark stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, ref StackCrawlMark stackMark, IntPtr pPrivHostBinder, Boolean forIntrospection)
   at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, ref StackCrawlMark stackMark, Boolean forIntrospection)
   at System.Reflection.Assembly.Load(String assemblyString)
   at System.UnitySerializationHolder.GetRealObject(StreamingContext context)
   at System.Runtime.Serialization.ObjectManager.ResolveObjectReference(ObjectHolder holder)
   at System.Runtime.Serialization.ObjectManager.DoFixups()
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
   [...]

If I add a handler for AppDomain.CurrentDomain.AssemblyResolve to load New.Interfaces instead of Old.Interfaces it throws another exception:

System.TypeLoadException : Could not load type 'Old.Interfaces.MyClass' from assembly 'New.Interfaces, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
   at System.Reflection.RuntimeAssembly.GetType(RuntimeAssembly assembly, String name, Boolean throwOnError, Boolean ignoreCase, ObjectHandleOnStack type)
   at System.Reflection.RuntimeAssembly.GetType(String name, Boolean throwOnError, Boolean ignoreCase)
   at System.UnitySerializationHolder.GetRealObject(StreamingContext context)
   at System.Runtime.Serialization.ObjectManager.ResolveObjectReference(ObjectHolder holder)
   at System.Runtime.Serialization.ObjectManager.DoFixups()

However, the BindToType method has already been called for the type Old.Interfaces.MyClass and as I said, in BindToType I'm not returning a single type which might have references to the old class.

Furthermore, if i change the binary data which gets deserialized, so that the occurrences of the string Old get replaced by New, the object graph gets finally loaded. I'm not very happy with this solution.

OTHER TIPS

I just ran into this issue myself, and it's pretty much not fix-able.

I moved some types from one assembly to another, and now files that I serialized in the older version cannot be deserialized. My SerializationBinder resolves every single type successfully (including the one that eventually causes the exception), but I still get the error. It doesn't crash until later, in section of code started by the DoFixup routine in the deserializer.

It turns out one of my serialized types has a member of type Type (confusing, I know). The Type information stored in this Type property, when deserialized, does NOT go through the SerializationBinder, but gets resolved internally and fails. AssemblyResolve will also not fix it.

The only way to deserialize this file, beyond manually parsing the file, would be to wrap up an older version with the previous assemblies that can read it, then save it to something type neutral.

I also ran into the very same issue: type was moved to another assembly, there is custom binder which do return proper type and yet TypeLoadException is generated.

And the thing which helped was actually this: https://stackoverflow.com/a/19490593/434298 I mean adding [assembly:TypeForwardedTo(typeof(TheType))] to assembly which had that type originally...

so for your issue I would suggest trying this and if will be needed make assembly with no real source code but just that [assembly:]

hopefully this will help another poor soul :|

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top