Linq to Xml VS XmlSerializer VS DataContractSerializer
В моем web method
я получаю объект некоторого третьего класса сущности С#. Класс сущности - это не что иное, как DataContract
. Этот класс сущностей довольно сложный и имеет свойства различных типов, некоторые свойства также являются коллекциями. Конечно, эти связанные типы также являются DataContracts.
Я хочу сериализовать этот объект DataContract в XML как часть бизнес-логики моего веб-сервиса. Я не могу использовать DataContractSerializer
напрямую (на объекте, который я получаю в веб-методе) просто потому, что XML-схема совсем другая. Таким образом, XML, сгенерированный DataContractSerializer, не будет проверяться на соответствие схеме.
Я не могу завершить подход, который я должен выполнить для реализации. Я мог бы подумать о следующих подходах реализации:
-
LINQ to XML. Это выглядит нормально, но мне нужно создать дерево XML (т.е. элементы или XML-представление экземпляра класса) вручную для каждого типа объекта. Поскольку существует много классов сущностей, и они связаны друг с другом, я думаю, что это слишком большая работа для записи XML-элементов вручную. Кроме того, мне придется продолжать модифицировать XML-дерево, когда класс сущности вводит новое свойство. Не только это, код, в котором я создаю XML-дерево, выглядел бы немного неуклюжим (по крайней мере, по внешнему виду) и будет сложнее поддерживать/изменять каким-то другим разработчиком в будущем; он/она должен будет смотреть на него так близко, чтобы понять, как генерируется этот XML.
-
XmlSerializer. Я могу написать свои собственные классы сущностей, которые представляют структуру XML, которую я хочу. Теперь мне нужно скопировать данные из входящего объекта в объект моих собственных классов. Так что это дополнительная работа (для .NET тоже при выполнении кода!). Затем я могу использовать XmlSerializer
для моего объекта для генерации XML. В этом случае мне придется создавать классы сущностей, и всякий раз, когда будет изменен сторонний объект, мне придется просто добавить новое свойство в свой класс. (с атрибутами XmlElement или XmlAttibute). Но люди рекомендуют DataContractSerializer
над этим, и поэтому я не хочу завершать это, если все аспекты не ясны для меня.
-
DataContractSerializer. Здесь снова я должен написать свой собственный класс сущностей, поскольку у меня нет контроля над сторонними DataContracts. И мне нужно скопировать данные из входящего объекта в объект моих собственных классов. Так что это дополнительная работа. Однако, поскольку DataContractSerializer не поддерживает атрибуты Xml, мне придется реализовать IXmlSerializable
и сгенерировать требуемый Xml в методе WriteXml
. DataContractSerializer быстрее, чем XmlSerializer, но опять-таки мне придется обрабатывать изменения (в WriteXml), если изменяется сторонний объект.
Вопросы:
- Какой подход лучше всего подходит для этого сценария, учитывая также производительность?
- Можете ли вы предложить лучший подход?
- Стоит ли считать
DataContractSerializer
(потому что он имеет лучшую производительность по сравнению с XmlSerilaizer
), когда класс входящей сущности может быть изменен?
- Должен ли LINQ действительно использоваться для сериализации? Или это действительно хорошо для вещей, кроме запросов?
- Может ли XmlSerializer быть предпочтительнее LINQ в таких случаях? Если да, то почему?
Ответы
Ответ 1
Я согласен с ответом @Werner Strydom.
Я решил использовать XmlSerializer
, потому что код становится поддерживаемым, и он предлагает производительность, которую я ожидаю. Самое главное, что он дает мне полный контроль над структурой XML.
Вот как я решил свою проблему:
Я создал классы сущностей (представляющие различные типы элементов Xml) в соответствии с моим требованием и передал экземпляр корневого класса (класс, представляющий корневой элемент) через XmlSerializer.
Небольшое использование LINQ
в случае отношения 1: M:
Где бы я ни хотел один элемент (скажем Employee
) при определенном node (скажем, Department
), я объявил свойство типа List<T>
. например public List<Employee> Employees
в классе Department
. В таких случаях XmlSerializer явно добавил элемент под названием Employees
(который является группировкой всех элементов Employee
) в Department
node. В таких случаях я использовал LINQ
(после того, как XmlSerializer сериализовал объект .NET), чтобы манипулировать XElement
(т.е. XML), сгенерированным XmlSerializer. Используя LINQ
, я просто поместил все узлы Employee
непосредственно под Department
node и удалил Employees
node.
Однако я получил ожидаемую производительность с помощью комбинации XmlSerializer
и LINQ
.
Даунсайд - это то, что все классы, которые я создал, должны были быть общедоступными, когда они вполне могли быть внутренними!
Почему бы не DataContractSerializer
и LINQ-to-XML
?
-
DataContractSerializer
не позволяет использовать атрибуты Xml (если я не реализую IXmlSerializable
). См. Типы , поддерживаемые DataContractSerializer.
-
LINQ-to-XML
(и IXmlSerializable
тоже) делает код неуклюжим при создании сложной структуры XML, и этот код определенно заставит других разработчиков царапать их головы, сохраняя/изменяя его.
Есть ли другой способ?
- Да. Как уже упоминалось @Werner Strydom, вы можете очень хорошо генерировать классы, используя
XSD.exe
или инструмент вроде Xsd2Code и работать с ними напрямую, если вы довольны результирующими классами.
Ответ 2
Я выберу XmlSerializer, потому что он наиболее удобен для пользовательской схемы (если у вас есть XSD). Когда вы закончите разработку системы, полностью проверьте ее производительность и определите, вызывает ли сериализация XML проблемы. Если это так, вы можете заменить его чем-то, что требует больше работы, и проверить его снова, чтобы узнать, есть ли какие-либо выгоды. Но если сериализация XML не является проблемой, то у вас есть код для поддержки.
Время, затрачиваемое на анализ небольшого фрагмента данных XML, может быть незначительным по сравнению с общением с базой данных или внешними системами. В системах с большой памятью (16 ГБ +) вы можете обнаружить, что GC является узким местом в .NET 4 и более ранних версиях (.NET 4.5 пытается решить эту проблему), особенно когда вы работаете с очень большими наборами данных и потоками.
Используйте AutoMapper для сопоставления объектов, созданных XSD.EXE с вашими объектами. Это позволит изменить дизайн базы данных, не оказывая влияния на веб-службу.
Одна вещь, которая отлично подходит для LINQ to XML, - это проверка XSD. Однако это влияет на производительность.
Ответ 3
Другой вариант - использовать LINQ и Reflection для создания универсального класса для сериализации вашего объекта в XML. Хороший пример этого можно найти на http://primecoder.blogspot.com/2010/09/how-to-serialize-objects-to-xml-using.html. Я не уверен, что ваш XML должен выглядеть в конце дня, но если это довольно просто, это может сделать трюк. Вам не нужно будет вносить изменения, поскольку классы сущностей добавляют/удаляют/изменяют свойства, и вы можете использовать их для всех своих объектов (и других проектов, если они хранятся в DLL-утилите).