10

Recently, we moved a part of our code to different project library.

Unfortunately, it appears that those data have been serialized into the database with a BinaryFormatter(don't ask me why, I don't know and I hate this idea).

Now I'm responsible to create an update tool that update the database(The tool is launched automatically by our software when it detects a database that need updates, based on version):

  1. Create new columns
  2. Deserialize the binary column
  3. Write the deserialized columns into the new column
  4. Delete the old binary columns

My problem is that when I try to deserialize, it tells me that :

Unable to find assembly 'MyOldAssemblyName, Version=2.0.0.0, Culture=neutral, PublicKeyToken=a5b9cb7043cc16da'.

But this assembly doesn't exists anymore. I've no issue to put this class in my "updater" project, but no way that I can keep this old project only to contains this file.

Is there a way to specify to the BinaryFormatter that it has to deserialize the Stream it receives with a specified class?

Or say that the assembly has been renamed, or ???

4

3 回答 3

7

要告诉它该类型已在程序集之间移动(但它保留了旧名称和命名空间),您有时可以使用 (在程序集中) [assembly:TypeForwardedTo(typeof(TheType))]。这里的“有时”是因为您需要使用typeof,这意味着您需要从旧程序集到新程序集的引用,这并不总是可能 - 但通常是(特别是如果您从 UI 层移动类型下到 POCO/DTO 层,因为 UI 通常引用 POCO/DTO)。

但是,如果您重命名了更改命名空间的类型,则需要您编写自定义“绑定器”(请参见此处)。

需要注意的BinaryFormatter是,它本质上是一个基于类型的序列化器,在版本控制或重构代码时总会遇到很多问题。如果类型不是“只写一次,就永远不要改变它”,那么我强烈建议使用更灵活的东西——基于契约而不是基于类型的东西。基本上,除了BinaryFormatter(or NetDataContractSerializer) 之外的任何东西:XmlSerializer, DataContractSerializer, protobuf-net, Json.NET 等中的任何一个都可以,并且不会关心您是否重新定位或重命名了一个类型。

于 2013-10-21T09:22:03.637 回答
5

事实上,我认为我找到了自己的解决方案。

我们可以给SerializationBinder二进制格式化程序一个,这将允许我们手动解析我们在流中找到的类。

更多信息在这里

于 2013-10-21T09:25:17.567 回答
0

我最近自己遇到了这个问题,并想发布我是如何设法解决这个问题的。正常序列化对象,一切的关键是当二进制格式化程序反序列化时,您可以使用活页夹。使用下面的活页夹,我简化了 MSDN 的解决方案,您需要做的就是将您使用的程序集的版本控制连同类名一起交还。

    public object DeserializeObject()
    {
        BinaryFormatter binaryFormatter = new BinaryFormatter();
        binaryFormatter.Binder = new VersionDeserializer();

        using (MemoryStream memoryStream = new MemoryStream())
        {
            try
            {
                memoryStream.Write(_data, _ptr, count);
                memoryStream.Seek(0, SeekOrigin.Begin);
                return binaryFormatter.Deserialize(memoryStream);
            }
            catch (Exception e)
            {
                return null;
            }
        }
    }

    sealed class VersionDeserializer: SerializationBinder
    {
        public override Type BindToType(string assemblyName, string typeName)
        {
            Type deserializeType = null;
            String thisAssembly = Assembly.GetExecutingAssembly().FullName;
            deserializeType = Type.GetType(String.Format("{0}, {1}",
                typeName, thisAssembly));

            return deserializeType;
        }
    }
于 2017-11-26T19:46:31.407 回答