Проблема десериализации: ошибка при десериализации из другой версии программы - PullRequest
0 голосов
/ 16 июня 2011

Я, наконец, решил опубликовать свою проблему, после нескольких часов, потраченных на поиск решений в Интернете и поиск некоторых.

[Контекст проблемы]

Iя разрабатываю приложение, которое будет развернуто в двух частях:

  • инструмент XML Importer: его роль заключается в загрузке / чтении XML-файла для заполнения некоторых структур данных, которые впоследствии сериализуются в двоичный файлfile.
  • приложение конечного пользователя: оно загрузит двоичный файл, сгенерированный импортером XML, и выполнит некоторые операции с восстановленными структурами данных.

Пока я использую толькоИмпортер XML для обеих целей (то есть сначала я загружаю xml и сохраняю его в двоичный файл, затем снова открываю импортер XML и загружаю свой двоичный файл).

[Актуальная проблема]

Это прекрасно работает, и я могу восстановить все данные, которые у меня были после загрузки XML, , пока я это делаюс той же сборкой моего XML Importer .Это нежизнеспособно, поскольку мне понадобятся как минимум две разные сборки: одна для импортера XML и одна для приложения конечного пользователя.Обратите внимание, что две версии XML Importer, которые я использую для своего тестирования, абсолютно одинаковы в отношении исходного кода и, следовательно, структур данных , единственное различие заключается в номере сборки (для принудительной другой сборки я простодобавить пробел куда-нибудь и построить заново).

Итак, я пытаюсь сделать следующее:

  • Создать версию моего XML Importer
  • Открыть XMLИмпортер, загрузите файл XML и сохраните полученные структуры данных в двоичный файл
  • Перестройте импортер XML
  • Откройте недавно созданный импортер XML, загрузите ранее созданный двоичный файл и восстановите мои структуры данных.

В настоящее время я получаю исключение:

SerializationException: Could not find type 'System.Collections.Generic.List`1[[Grid, 74b7fa2fcc11e47f8bc966e9110610a6, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]'.
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadType (System.IO.BinaryReader reader, TypeTag code)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadTypeMetadata (System.IO.BinaryReader reader, Boolean isRuntimeObject, Boolean hasTypeInfo)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObjectInstance (System.IO.BinaryReader reader, Boolean isRuntimeObject, Boolean hasTypeInfo, System.Int64& objectId, System.Object& value, System.Runtime.Serialization.SerializationInfo& info)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObject (BinaryElement element, System.IO.BinaryReader reader, System.Int64& objectId, System.Object& value, System.Runtime.Serialization.SerializationInfo& info)

Для вашей информации (не знаю, полезен он или нет), фактический тип, который он пытается десериализовать, являетсяList, Grid - это пользовательский класс (который корректно сериализуем, как я могу сделать, используя ту же версию XML Importer).

[Потенциальное решение]

Я верю, что это происходит откуда-то из Ассамблеи, так как я читаю много постов и статей об этом.Тем не менее, у меня уже есть пользовательский Binder, который учитывает различия в именах сборок и выглядит так:

public sealed class VersionDeserializationBinder : SerializationBinder
{ 
    public override Type BindToType( string assemblyName, string typeName )
    { 
        if ( !string.IsNullOrEmpty( assemblyName ) && !string.IsNullOrEmpty( typeName ) )
        { 
            Type typeToDeserialize = null; 
            assemblyName = Assembly.GetExecutingAssembly().FullName; 
            // The following line of code returns the type. 
            typeToDeserialize = Type.GetType( String.Format( "{0}, {1}", typeName, assemblyName ) ); 

            return typeToDeserialize; 
        } 

        return null; 
    }
}

, который я назначаю BinaryFormatter перед десериализацией здесь:У кого-нибудь из вас есть идея, как я могу это исправить?Было бы здорово, довольно, пожалуйста:)

Ответы [ 3 ]

1 голос
/ 17 сентября 2013

Я только что наткнулся на вашу ветку, пока у меня была такая же проблема.Особенно ваш пример кода с SerializationBinder мне очень помог.Мне просто пришлось немного изменить его, чтобы показать разницу между моими сборками и сборками Microsoft.Надеюсь, вам это тоже поможет:

sealed class VersionDeserializationBinder : SerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName)
    {
        Type typeToDeserialize = null;
        string currentAssemblyInfo = Assembly.GetExecutingAssembly().FullName;

        //my modification
        string currentAssemblyName = currentAssemblyInfo.Split(',')[0];
        if (assemblyName.StartsWith(currentAssemblyName))assemblyName = currentAssemblyInfo;

        typeToDeserialize = Type.GetType(string.Format("{0}, {1}", typeName, assemblyName));
        return typeToDeserialize;
    }
}
1 голос
/ 16 июня 2011

Переместите рабочие биты в отдельную сборку и используйте сборку как в «сервере», так и в «клиенте». Исходя из вашего объяснения проблемы, это должно обойти проблему «неправильной версии», если это основная проблема. Я также взял бы любые «модели» (то есть биты состояния, такие как Grid) для проекта модели предметной области и использовал их в обоих местах.

0 голосов
/ 16 июня 2011

Я полагаю, что проблема в том, что вы говорите ему искать List <> в исполняемой сборке, тогда как на самом деле это в сборке System. Вам следует переустанавливать имя сборки в подшивке только в том случае, если исходная сборка принадлежит вам.

Кроме того, вам может потребоваться обработать типы параметров для родовых объектов, в частности, в связывателе, проанализировав имя типа и убедившись, что типы параметров не являются специфичными для внешней сборки, когда вы возвращаете параметризованный универсальный тип.

...