Поддерживать совместимость сериализированных данных .NET при перемещении классов - PullRequest
2 голосов
/ 07 января 2011

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

Пока что я перенес классы в новый проект. Я сохранил те же пространства имен, что и в старом проекте. Но этого было недостаточно для чтения объектов. Я получаю исключение SerializationException, в котором говорится «Ошибка разбора, тип не связан с ключом Xml a1 MyCorp.MyApp.DatabaseRoot MyCorp.MyApp». Глядя на сгенерированный SOAP XML, ссылки на схемы изменились. Например, у меня есть класс MyCorp.Dashboard.DatabaseRoot , изначально в проекте DashboardLibrary . Это было перемещено в проект DashboardData (но все еще используется пространство имен MyCorp.Dashboard.DatabaseRoot ). XML изменился следующим образом:

Orig: <a1:DatabaseRoot id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/MyCorp.Dashboard/MyCorp.Dashboard">
New:  <a1:DatabaseRoot id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/MyCorp.Dashboard/DashboardData">

Итак, мои вопросы

  • Можно ли перемещать классы и сохранять совместимость? Я, кажется, близок к тому, чтобы снять его.
  • Если это так, как мне управлять информацией о последней битовой схеме (MyCorp.Dashboard vs. DashboardData). Кажется, что оригинал основан на расположении каталога, а второй - на имени проекта. Я пытался изменить структуру каталогов в новом проекте, но мне не повезло. Что-то еще мне не хватает?

Спасибо.

1 Ответ

5 голосов
/ 07 января 2011

Вам необходимо реализовать пользовательский SerializationBinder.Переопределите метод BindToType, чтобы выбрать тип для загрузки на основе его имени:

public override Type BindToType(string assemblyName, string typeName)
{
    if (assemblyName == "MyOldAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
    {
        if (typeName == "MyOldNamespace.MyOldClass")
        {
            return typeof(MyNewClass);
        }
    }
    // Fall back to the default behavior, which will throw
    // a SerializationException if the old assembly can't be found
    return null;
}

(это очень простая реализация, в реальном сценарии вы, вероятно, будете использоватьулучшенная логика сопоставления).

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

После того, как у вас есть пользовательский SerializationBinder, вам просто нужно присвоить его свойству Binder объектаотформатируйте, и используйте его оттуда как обычно.

Если вам нужно изменить структуру типов (добавить или переименовать поля, изменить типы ...), вам нужно будет реализовать ISerializationSurrogate для сопоставления старых данных с новой структурой типа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...