【问题标题】:Version Tolerant Serialization - How to find AssemblyName of the original版本容错序列化 - 如何找到原始的 AssemblyName
【发布时间】:2009-06-14 16:08:53
【问题描述】:

在 .NET 2.0(及更高版本,我想)中,版本容忍序列化将成功地从对象所在的旧版本程序集反序列化序列化对象。

当我使用十六进制查看器打开这种二进制格式的序列化流时(简单的拖放到 VS 中就可以了),我可以看到该流中包含程序集信息。

在反序列化过程中,是否有一种方法可以检索此信息?例如,这可用于在阅读旧内容时对已知问题进行修复。

更新: 看起来它无法完成(除了改变类本身,如 Paul Betts 的回答,也没有测试)那么还有其他方法可以读取这个值吗?二进制格式发布了吗?

【问题讨论】:

标签: c# serialization


【解决方案1】:

我在写this CodeProject article 时第一手发现了这些序列化问题(滚动到“从磁盘加载目录”,大约一半)。

基本上,我正在使用 ASP.NET 应用程序序列化某些内容 - 重新启动 IIS 应用程序后无法读取序列化数据(由于 ASP.NET 所做的整个动态编译/临时程序集缓存/等)!哎哟!

无论如何,我的第一点是反序列化过程中抛出的异常包含强名称

找不到程序集 h4octhiw,Version=0.0.0.0,Culture=neutral,PublicKeyToken=null

显然你是正确的,你想要的信息在“某处”。理论上(是的,这是一个可怕的想法)您可以捕获序列化异常并解析旧版本详细信息的错误(当然“当前”反序列化将在不抛出的情况下工作)......但也可能有更好的方法...... .

第二点与我实施的解决方案有关(使用this info)。我写了一个自定义的System.Runtime.Serialization.SerializationBinder:下面显示的代码作为示例。

public class CatalogBinder: System.Runtime.Serialization.SerializationBinder
{
    public override Type BindToType (string assemblyName, string typeName) 
    { 
        // get the 'fully qualified (ie inc namespace) type name' into an array
        string[] typeInfo = typeName.Split('.');
        // because the last item is the class name, which we're going to 
        // 'look for' in *this* namespace/assembly
        string className=typeInfo[typeInfo.Length -1];
        if (className.Equals("Catalog"))
        {
            return typeof (Catalog);
        }
        else if (className.Equals("Word"))
        {
            return typeof (Word);
        }
        if (className.Equals("File"))
        {
            return typeof (File);
        }
        else
        {    // pass back exactly what was passed in!
            return Type.GetType(string.Format( "{0}, {1}", typeName, 
                                assemblyName));
        }
    } 
}

基本上BindToType 正在通过反序列化过程“替换”一个已知类型来替代最初用于序列化该对象的类型。我只使用typeName,但assemblyName 可能包含您所追求的信息,并且自定义SerializationBinder 可能是您应该调查“使用”它的方法。

仅供参考,上面的代码是这样“连接”的:

System.Runtime.Serialization.IFormatter formatter = 
    new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
formatter.Binder = new CatalogBinder(); // THIS IS THE IMPORTANT BIT
object deserializedObject = formatter.Deserialize(stream); 

【讨论】:

  • 这正是我想要的。
【解决方案2】:

向所有序列化类添加一个名为 AssemblyInfo 的字段,该字段设置为 Assembly.GetExecutingAssembly().FullName

【讨论】:

    【解决方案3】:

    使用 Lutz Roeders(现为 Red Gate's)Reflector

    System.Runtime.Serialization.Formatters.Binary.__BinaryParser 类在内部由BinaryFormatterDeserialize 方法用于执行实际解析。

    在反射器中四处寻找可能会让您了解如何预读二进制标头并确定版本信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-11
      • 2012-06-22
      • 2015-05-23
      相关资源
      最近更新 更多