版本容错序列化 - 如何查找原始的AssemblyName

时间:2009-06-04 14:36:21

标签: c# serialization

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

当我使用十六进制查看器打开这样一个二进制格式化的序列化流时(一个简单的拖放到VS中)我可以看到这个流中包含的汇编信息。

在反序列化期间,是否有检索此信息的方法?例如,这可用于在阅读旧内容时将修正应用于已知问题。

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

3 个答案:

答案 0 :(得分:5)

我在编写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); 

答案 1 :(得分:1)

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

答案 2 :(得分:0)

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

System.Runtime.Serialization.Formatters.Binary.__BinaryParser 类在BinaryFormatter的{​​{1}}方法内部使用,以进行实际解析。

在反射器中四处寻找可能会为您提供有关如何预读二进制标头和确定版本信息的想法。