反序列化跨程序集移动的类型

时间:2013-01-08 15:00:33

标签: c# .net binaryformatter binary-serialization

我有一堆类型已从一个程序集移动到另一个程序集。我试图通过使用 SerializationBinder 反序列化使用旧程序集序列化的数据到新程序集中的类型。

编辑:程序集的根名称空间与程序集名称相同。旧组件不再存在。

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;
        }
    }

反序列化代码看起来像这样 -

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

当我尝试反序列化时,我在尝试加载旧程序集时遇到错误。

  

无法加载文件或程序集“旧程序集”或其中一个   依赖。系统找不到指定的文件。

3 个答案:

答案 0 :(得分:1)

我想我也遇到了同样的问题。

我的SerializationBinder的BindToType方法没有发出任何类型,它引用旧的程序集,但仍然,BinaryFormatter尝试加载旧的程序集:

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)
   [...]

如果我为AppDomain.CurrentDomain.AssemblyResolve添加处理程序以加载New.Interfaces而不是Old.Interfaces,则会引发另一个异常:

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()

但是,已经为类型Old.Interfaces.MyClass调用了BindToType方法,正如我所说,在BindToType中,我没有返回可能引用旧类的单个类型。

此外,如果我更改了反序列化的二进制数据,以便字符串Old的出现被New替换,则最终会加载对象图。我对这个解决方案不太满意。

答案 1 :(得分:0)

我只是自己碰到这个问题,而且几乎无法修复。

我将某些类型从一种程序集移动到了另一种程序集,现在我不能反序列化在较早版本中序列化的文件。我的SerializationBinder成功解析了每种类型(包括最终导致异常的一种),但我仍然收到错误。直到稍后,它才会在反序列化程序中由DoFixup例程启动的代码部分中崩溃。

事实证明,我的一种序列化类型的成员类型为 Type (我知道这很混乱)。反序列化时,存储在此Type属性中的Type信息不会通过SerializationBinder,而是在内部进行解析并失败。 AssemblyResolve也不会修复它。

除了手动解析文件之外,反序列化此文件的唯一方法是将旧版本与可以读取该文件的先前程序集包装在一起,然后将其保存为中性类型。

答案 2 :(得分:0)

我也遇到了同样的问题:类型已移至另一个程序集,有自定义活页夹,该活页夹确实返回正确的类型,但仍生成TypeLoadException。

真正有用的是:https://stackoverflow.com/a/19490593/434298 我的意思是将[assembly:TypeForwardedTo(typeof(TheType))]添加到最初具有该类型的程序集中...

因此,对于您的问题,我建议您尝试一下,如果需要的话,请使用没有[em]真正源代码的程序集,而只需使用[assembly:]

希望这会帮助另一个可怜的灵魂:|