Подводные камни XmlSerializer

Мне очень нравится возможность .NET выполнять xml сериализацию. Очень удобно сохранять и загружать практически любые данные.

Делается это очень просто:

  1. создаем XmlSerializer, передавая тип класса, который нужно сериализовать,
  2. вызываем методы Serialize или Deserialize, в качестве параметра используем файловый поток.

Среда .NET генерирует специальную сборку, в которой находится код, выполняющий преобразование программных объектов в данные и наоборот. Сам процесс сериализации выполняется достаточно быстро. К примеру, загрузка списка файлов пользователя p2p сети, выполняемая библиотекой FlowLib, была в 20 раз (!!!) медленнее чем при использовании XmlSerializer. После замены этого модуля Клиент О-ГО 2 стал открывать списки быстрее, чем неуправляемые клиенты семейства StrongDC. 

К сожалению, есть у метода и недостатки. 

Проблемы XmlSerializer

Генерация сборки

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

Решение

Перед выполнением генерации сборки XmlSerializer выполняет поиск уже существующей. Таким образом, если мы предоставим ему нужную сборку генерация производиться не будет. Используем утилиту sgen для генерации сборки, полученный файл вида название_проекта.XmlSerializers.dll включаем в проект.

Утилита sgen генерирует сериализаторы для всех типов в сборке, либо для какого-то одного. Если нужны всего несколько типов, можно использовать утилиту XGenPlus. В этом случае будут созданы конкретные классы сериализаторов для каждого выбранного типа. Придется заменить их в коде вручную.

Ошибки Microsoft

Еще одна проблема связана с конструкторами XmlSerializer. Дело в том, что использование конструкторов, отличных от XmlSerializer(Type) вызывает генерацию и компиляцию сборки при каждом создании экземпляра во время работы приложения. Это ошибка .NET Framework, и, похоже, исправлена она не будет.

Решение

Использовать только конструктор XmlSerializer(Type)

Спецсимволы

Последняя известная мне проблема — валидация xml файла. Если xml файл содержит спецсимволы, не допустимые стандартом мы получим исключение следующего вида:

InvalidOperationException : шестнадцатеричное значение 0x1D, является недопустимым знаком. Строка 732, позиция 215.

Решение

Я не смог найти элегантного решения этой проблемы. Поэтому используется обертка над FileStream, которая заменяет все проблемные символы. Скачать


  • justserega

    Классно! Не знал, что генерируется сборка, а тем более, что ее можно использовать повторно. Кстати есть ещё более производительное решение — protobuf. По скорости значительно лучше xml, из минусов он бинарный (но зачем в такие файлы руками лазить). Юзаю вот эту библиотеку — http://code.google.com/p/protobuf/ очень доволен!

    • Vladislav Pozdnyakov

      Поймет ли она, если добавить новые поля в класс и попробовать загрузить старые данные?

      • justserega

        Поймет, формат расширяемый. В одном проекте очень активно юзается, поля постоянно добавляются — полет нормальный!

      • justserega

        Правильная ссылка на библиотеку для .Net http://code.google.com/p/protobuf-net/

        • Vladislav Pozdnyakov

          Спасибо, обязательно попробую, когда подвернется возможность.

    • Vladislav Pozdnyakov

      В утопии я использую ручную сериализацию через BinaryWriter, еще меньше размера и больше скорости 🙂

    • http://aspect.myopenid.com/ Constantine

      Что протобаф, что хмл — форматы обмена данными, для хранения не особо приспособлены.

  • http://aspect.myopenid.com/ Constantine

    Почему бы не хранить всё это дело в sqlite как взрослые дяди. Ковырять многометровый хмл не труЪ

    • Vladislav Pozdnyakov

      Скорость разработки разная. Изменилась структура класса — нужно менять таблицу, переписывать запросы. В случае с protofab и xml можно изменить объектную модель и все автоматом будет работать.

      • http://aspect.myopenid.com/ Constantine

        Для этого есть миграторы схемы. В любом случае, проблема обновления клиентского xml не пропадает.