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

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

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

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

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

我在编写CodeProject文章时亲自发现了这些序列化问题(滚动到’从磁盘加载目录’,大约一半)。

基本上我用ASP.NET应用程序序列化了一些东西 – 在重新启动IIS应用程序之后无法读取序列化数据(由于ASP.NET所做的整个动态编译/临时程序集缓存/等)! 哎哟!

无论如何,我的第一点是在反序列化期间抛出的exception包括强名称

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

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

第二点涉及我实施的解决方案(使用此信息 )。 我写了一个自定义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); 

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

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

System.Runtime.Serialization.Formatters.Binary.__BinaryParser类由BinaryFormatterDeserialize方法在内部使用,以进行实际的解析。

在reflection器中四处寻找可能会给你如何预读二进制头并确定版本信息的想法。