在执行二进制反序列化之前,请检查应用程序版本



我有一个简单的应用程序,在其中我将一个包含所有概要文件对象的概要文件处理程序序列化到磁盘。它工作得很好。。。但我突然想到,未来会有问题。

下次更新软件时,配置文件可能会发生更改,包含新的字段和属性,或者某些类型可能已经更改。当试图从早期版本反序列化时,这当然会破坏程序。

解决这个问题最简单、最直接的方法是什么?我想应该有一种方法可以在二进制文件中添加一些头位,然后以某种方式进行检查。

这是我的序列化程序方法:

private void SaveProfilesToDisk()
{
    var serializer = new BinaryFormatter();
    string filename = Path.Combine(Environment.CurrentDirectory, @"MyAppMyApp.profiles");
    using (FileStream fileStream = File.OpenWrite(filename))
    {
        serializer.Serialize(fileStream, _profileHandler);
    }
}

这就是我反序列化它的方式:

 private ProfileHandler LoadProfilesFromDisk()
    {
        var serializer = new BinaryFormatter();
        string filename = Path.Combine(Environment.CurrentDirectory, @"MyAppMyApp.profiles");
        using (FileStream fileStream = File.OpenRead(filename))
        {
            return (ProfileHandler) serializer.Deserialize(fileStream);
        }
    }

我可以简单地告诉用户保存文件已经过时,重命名/删除它并创建一个新文件。

EDIT: 在重读该问题时,我意识到值得注意的是AssemblyResolve事件将接收反序列化程序试图解决的程序集版本。如果只需要不兼容的版本消息,则可以在程序集名称为程序集名称且版本与当前版本不同的位置设置陷阱,并相应地进行提示

我同意@smore的观点,即最简单的方法是使用XmlSerialization,因为它可以反序列化发生非中断更改的以前版本的配置文件。XmlSerializer将简单地忽略不存在的字段,并愉快地反序列化存在的字段。

如果出于某种原因确实需要二进制序列化,并且应用程序可以使用对象的旧版本,那么实现这一点的一种方法是不关心解序列化时的版本,而只是尝试匹配和反序列化任何可能的属性。对于非中断性更改,如添加新属性,您应该能够毫无问题地反序列化旧版本。

类型解析事件的第一个寄存器:

AppDomain.CurrentDomain.TypeResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

接下来,添加类型解析方法,对于感兴趣的程序集,返回这些程序集的当前版本。这里有一个例子,我做了这样的事情:

Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) {
            Assembly result = null;
            foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) {
                AssemblyName assemblyName = assembly.GetName();
                if (args.Name.StartsWith(assemblyName.Name)) {
                    this.LogInfo("Assembly "" + args.Name + "" resolved to "" + assembly.Location + "".");
                    result = assembly;
                    break;
                }
            }
            if(result != null){
                return result;
            }else{
                this.LogError("Assembly resolution failure. An assembly named "" + args.Name + "" was not found.");
                return null;
            }
        }

如果我的想法正确的话,这应该将类型解析为新版本,并允许您反序列化发生了不间断更改的旧版本。对于中断更改,最简单的事情就是捕获SerializationException并相应地提示用户。

最新更新