none
二进制序列化 版本问题 RRS feed

  • 问题

  • 是这样的 我最近在写一个软件,这个软件只有一个exe文件

    这个软件的存档是由 .NET的二进制序列化 功能实现的。一开始都运行正常,但是当我准备升级程序的版本号时(比如从1.1升级到1.2),我发现以前的存档全都不能读取了,系统提示我:(而且我只是单纯的改了一下版本号,没有修改任何代码)

    未能加载文件或程序集“*****, Version=1.1.0.0, Culture=neutral, PublicKeyToken=80599ddbc31265c6”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。 (异常来自 HRESULT:0x80131040)

    就是说原来生成序列化文件时,我的程序是1.1,可是现在反序列化时程序已经升级到了1.2(并且1.1已经删除了),可是他还在找1.1…… (而且即便我不删除1.1的程序也不行,在用1.2的程序反序列化时系统扔出一个InvalidCast 提示我:无法从1.1版本的类型转换成1.2版本的类型)

    很郁闷么……

    然后我尝试修改了BinaryFormatter.Binder 代码是这样:

    var ser = new BinaryFormatter() { Binder = new CradeVersionSerBinder() };
    
    class CradeVersionSerBinder : SerializationBinder
    {
    HashSet<string> SupportVersion; // 我的程序能够支持的旧的版本
    Assembly MyNowAssembly = Assembly.GetAssembly(typeof(CradeVersionSerBinder));
    
    Assembly assemblyResolver(AssemblyName name)
    {
        if (SupportVersion.Contains(name.FullName))
            return MyNowAssembly;
        else return Assembly.Load(name);
    }
    Type typeResolver(Assembly assembly, string typename, bool ignoreCase)
    {
        if (assembly == null)
            assembly = CoreAssembly;
        return assembly.GetType(typename, false, ignoreCase);
    }
    public override Type BindToType(string assemblyName, string typeName)
    {
        return Type.GetType(String.Format("{0}, {1}", typeName, assemblyName), assemblyResolver, typeResolver);
    }
    }
    

    但是错误依旧存在,.NET报错说: “调用的目标发生了异常。” 然后这个异常的InnerException 还是无法找到 Version=1.1.0.0的程序集……

    谢谢!感激不尽!

    2013年2月27日 2:22

答案

  • 嗯 我想我找到了解决方法了

    就是增加一个配置文件:

    <configuration>
      <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
          <dependentAssembly>
            <assemblyIdentity name="GradeExcel" publicKeyToken="80599ddbc31265c6" culture="neutral"/>
            <bindingRedirect oldVersion="1.1.20.0-1.1.30.0" newVersion="1.1.31.0" />
          </dependentAssembly>
        </assemblyBinding>
      </runtime>
    </configuration>
    
    把旧版本全部重定向到新版本就可以了…………


    2013年2月27日 7:12

全部回复

  • 你调试时候发现确实你的程序已经更新到了1.2?

    还有没有什么引用类库啥的还是1.1?


    Click here to donate your rice to the poor
    Click to Donate
    Click to feed Dogs & Cats

    2013年2月27日 2:52
    版主
  • 嗯 我的项目就一个exe程序 我直接改了这个 [assembly: AssemblyVersion("1.2.0.0")] 呀,所以说更新应该是肯定的吧

    而且我的项目就一个exe程序,我准备序列化的类型是我自己定义的,就在那个exe程序里面,引用的所有库都是.NET的

    2013年2月27日 2:56
  • 而且我现在用 AssemblyFormat 也试过了

    var ser = new BinaryFormatter() { AssemblyFormat = FormatterAssemblyStyle.Simple };

    还是不能读取旧版本文件…… (抛出的异常 还是找不到1.1)

    2013年2月27日 2:59
  • 而且我的程序要序列化的对象中还包含了一个 我自己定义的委托

    我用16进制编辑器查看了二进制序列化生成的文件,一共有4个地方是 GradeExcel, Version=1.1.0.0, Culture=neutral, PublicKeyToken=80599ddbc31265c 当我前3个不变,把第4个改为: GradeExcel, Version=1.2.0.0, Culture=neutral, PublicKeyToken=80599ddbc31265c 时候 我发现我的程序能够运行了,就是说也许正是这部分导致了错误

    而且这部分是:

    GradeExcel.RecordTipDescribe+DataChangeEvent .?..NGradeExcel, Version=1.1.0.0, Culture=neutral, PublicKeyToken=80599ddbc31265c6

    其中GradeExcel.RecordTipDescribe是我定义的一个类型,在这类型下我还定义了一个委托:public delegate void DataChangeEvent(Student stu, object to); // Student 也是我定义的

    所以我想正是这部分委托引起了序列化的错误


    2013年2月27日 3:24
  • 这个问题比较奇怪:

    你尝试在设计器(切换到属性面板中)修改,然后重新编译看看。


    Click here to donate your rice to the poor
    Click to Donate
    Click to feed Dogs & Cats

    2013年2月27日 3:34
    版主
  • 嗯 我想我查明了错误的原因了、

    在我准备序列化的类型中有一个 我自己定义的DataChangeEvent 委托,在序列化的时候会记录这个委托的类型信息(包括了程序集版本)

    当我反序列化的时候,反序列化器会调用我写的CradeVersionSerBinder.BindToType去解析类型

    但是反序列化器却从来没有对DataChangeEvent 委托的类型信息调用BindToType!

    就是说反序列化器对其他类都一视同仁的调用了我的BindToType,然后我的BindToType去选取1.2的版本

    但是反序列化器却忘记了我的DataChangeEvent 委托,他只是自己默认调用1.1的程序及版本,所以就出错了。

    准确的来说是这样, 我让程序输出所有调用了BindToType的typename:

    public override Type BindToType(string assemblyName, string typeName)
    {
        Console.WriteLine(String.Format("{0}, {1}", typeName, assemblyName));
        return Type.GetType(String.Format("{0}, {1}", typeName, assemblyName), assemblyResolver, typeResolver);
    }

    然后呢,输出了很多东西,唯独没有DataChangeEvent !!!


    2013年2月27日 3:56
  • 不知道这是不是.NET的一个BUG(我现在用的是.NET 4.0)
    2013年2月27日 4:02
  • 嗯 我想我找到了解决方法了

    就是增加一个配置文件:

    <configuration>
      <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
          <dependentAssembly>
            <assemblyIdentity name="GradeExcel" publicKeyToken="80599ddbc31265c6" culture="neutral"/>
            <bindingRedirect oldVersion="1.1.20.0-1.1.30.0" newVersion="1.1.31.0" />
          </dependentAssembly>
        </assemblyBinding>
      </runtime>
    </configuration>
    
    把旧版本全部重定向到新版本就可以了…………


    2013年2月27日 7:12