XML-cериализация данных в .NET. Что такое XML-сериализация?
Сериализация — это процесс преобразования объекта в форму, которая подготовлена для передачи. К примеру, вы можете сериализовать объект, чтобы передать его по сети с применением HTTP-протокола между сервером и клиентом. Или, наоборот, десериализовать объект, воссоздав его из потока.
Если говорить об XML-сериализации, то при ней в XML-поток сериализуются лишь значения свойств объекта и открытые поля. То есть при XML-сериализации информация о типе не учитывается. Допустим, есть объект Book, существующий в пространстве имён Library. При этом не существует гарантии, что он сможет десериализоваться в объект аналогичного типа.
Примечание: XML-сериализация не преобразует методы, индексаторы, закрытые поля или read-only свойства (кроме коллекций для чтения). Для XML-сериализации всех свойств объекта и полей (как закрытых, так и открытых), применяйте вместо XML-сериализации
XML-cериализация. Класс XmlSerializer
Центральный класс XML-сериализации — это
Для описания данных в объектах используются конструкции языка программирования (классы, поля, свойства, типы примитивов, массивы и даже встроенные XML в виде объектов XmlAttribute либо XmlElement). Можно создавать свои классы, аннотируемые атрибутами, либо использовать инструмент определения схемы XML в целях создания классов на основании существующей схемы XML.
Если есть в наличии схема XML, вы без проблем запустите инструмент определения схемы XML и сможете создать набор классов, аннотируемых атрибутами и имеющих строгий тип схемы. Во время XML-сериализации экземпляра этого класса созданный XML будет отвечать схеме XML. С помощью такого класса можно будет создать код, применяя объектную модель, которой можно будет не только легко управлять, но и гарантировать, что созданный XML соответствует схеме XML. Это альтернативный вариант применения других классов в .NET Framework для выполнения анализа и записи в поток XML, к примеру, классов XmlWriter и XmlReader (классы дают возможность анализировать любой XML-поток). Если же предполагается, что XML-поток отвечает известной схеме XML, лучше сразу использовать XmlSerializer.
XML-поток, созданный классом XmlSerializer, управляется атрибутами. Они позволяют задавать имена элемента и атрибута потока XML, пространство XML-имён и т. п. Класс XmlSerializer способен сериализовывать объект, создавая XML-поток с кодировкой SOAP. Кроме того, XmlSerializer создаёт SOAP-сообщения, сформированные и переданные в веб-службы XML. Чтобы управлять SOAP-сообщениями, можно применять атрибуты к возвращаемым значениям, классам, полям и параметрам, обнаруженным в файле веб-службы XML (как правило, это файл ASMX).
Также можно использовать оба атрибута, которые указаны в перечнях «Атрибуты управления XML-сериализацией» и «Атрибуты управления сериализацией с SOAP-кодировкой», ведь веб-служба XML применяет или литеральный стиль, или стиль с SOAP-кодировкой.
Вопросы безопасности по отношению к приложениям с XmlSerializer
Когда создаётся приложение, использующее XmlSerializer, помните о ряде особенностей и некоторых вероятных последствиях:
1.XmlSerializer, создавая файлы C# (CS), компилирует их в DLL-файлы в каталоге, названном переменной среды TEMP. Благодаря DLL-файлам и происходит XML-сериализация.
Примечание: такие сборки XML-сериализации вы можете создавать заблаговременно, подписывая их посредством SGen.exe. Но этот способ невозможен к использованию на сервере web-служб. Иначе говоря, метод подходит лишь для клиентов и для выполнения XML-сериализации вручную.
DLL-файлы и код уязвимы для вредоносных процессов в момент их создания и компиляции. На ПК с Microsoft Windows NT (4.0 или более поздней версии) 2 либо более пользователей могут обладать совместным доступом к каталогу TEMP. Это несёт угрозу, если у 2-х учётных записей прописаны разные привилегии безопасности, а приложение запускается с использованием XmlSerializer из той учётной записи, которая имеет более высокие привилегии. В этом случае какой-нибудь из юзеров способен нарушить безопасность ПК, заменив или файл DLL, или компилируемый файл CS. Для устранения уязвимости убедитесь, что в каждой учётке на ПК есть отдельный профиль. При этом по умолчанию переменная среды TEMP указывает на различные каталоги для каждой отдельной учётной записи.
2.Если злоумышленник осуществляет отправку непрерывного потока XML-данных на веб-сервер (речь идёт об атаке типа «отказ в обслуживании»), то XmlSerializer продолжает обработку данных до тех пор, пока на эту самую обработку не будут затрачены все ресурсы системы.
Данный вид атаки можно заблокировать, используя ПК, где запущены службы Internet Information Services (IIS), а приложение функционирует в среде IIS. В IIS-службах применяется логический элемент. Он не обрабатывает те потоки, размер которых выше заданного значения (по умолчанию это значение равно 4 Кб). Если же создаётся приложение, которое не использует IIS-службы и выполняет XML-сериализацию посредством XmlSerializer, нужно реализовать схожий логический элемент, который и будет блокировать соответствующие атаки.
3.XmlSerializer сериализует данные, запуская соответствующий код с применением любого переданного ему типа. Здесь вредоносный объект может быть опасным в 2-х случаях. Например, возможен запуск вредоносного кода либо ввод его в файл C#, сформированный XmlSerializer. В случае запуска, если вредоносный объект попытается запустить разрушительный процесс, система управления доступом для кода предотвратит повреждения. Во втором случае вероятность атаки минимальна, однако меры предосторожности не помешают. Например, никогда не стоит сериализовывать данные недоверенного или неизвестного типа.
4.Сериализованные конфиденциальные данные бывают уязвимы. После того, как XmlSerializer сериализовал данные, они могут сохраняться в XML-файле либо другом хранилище данных. Когда хранилище доступно для прочих процессов или его видно в Интернете/интрасети, данные можно украсть. К примеру, когда создаётся приложение, сериализующее заказы с номерами кредитных карт, эти конфиденциальные данные весьма важны. А чтобы предотвратить их злонамеренное использование, защищайте хранилище и принимайте меры, делающие его закрытым.
Сериализация простого класса
Давайте посмотрим на участок кода с базовым классом с открытым полем:
Public Class OrderForm Public OrderDate As DateTime End Class public class OrderForm { public DateTime OrderDate; }
Если мы решим выполнить XML-сериализацию экземпляра данного класса, процесс будет выглядеть так:
<OrderForm> <OrderDate>12/12/01</OrderDate> </OrderForm>
Какие элементы можно сериализовать?
Используя XmlSerializer, вы сможете сериализовать: — открытые свойства чтения/записи, а также поля открытых классов; — классы, которые реализуют IEnumerable либо ICollection.
Примечание: XML-сериализации подлежат лишь коллекции, но не открытые свойства: — объекты XmlElement; — объекты DataSet; — объекты XmlNode.
Преимущества XML-сериализации
XmlSerializer обеспечивает гибкое и всестороннее управление XML-сериализацией объекта. Во время создания веб-служб XML к классам и членам вы сможете применять атрибуты, управляющие сериализацией. Это делается, чтобы выходные XML-данные отвечали определённой схеме.
Допустим, XmlSerializer позволяет: — указывать, следует ли кодировать поле либо свойство в качестве атрибута или элемента; — указывать используемое пространство XML-имен; — указывать имя элемента либо атрибута, когда имя поля либо свойства неправильны.
Очередной плюс XML-сериализации — это отсутствие ограничений для создаваемых приложений, ведь создаваемый XML-поток отвечает определённой схеме. К примеру, есть схема, использующаяся для описания книг. В ней присутствуют такие элементы, как автор, название, издатель, номер ISBN. Вы сможете разработать приложение, обрабатывающее XML-данные любым удобным способом. Единственным требованием в любом случае будет соответствие XML-потока указанной схеме языка определения XML-схемы (XSD).
Вопросы, связанные с XML-сериализацией
Используя XmlSerializer, обращайте внимание на ряд аспектов:
— инструмент Sgen.exe предназначен лишь для создания сборок XML-сериализации, что необходимо при обеспечении оптимальной производительности;
— XML-сериализованные данные включают только непосредственно сами данные и структуру классов. При этом информация о сборке и удостоверения типа не сохраняются;
— методы сериализовать нельзя;
— можно сериализовать исключительно открытые свойства и поля, причём для свойств нужно указать открытые методы доступа (get и set). Когда нужно сериализовать закрытые данные, используйте не XML-сериализацию, а класс
Класс, который реализует IEnumerable, должен реализовывать открытый Add-метод, принимающий 1 параметр. При этом параметр метода Add должен быть полиморфным типу, который возвращается из свойства
Класс, который реализует ICollection, в дополнение к IEnumerable, должен иметь открытое индексированное свойство под названием Item (индексатор в C#), принимающее целое число. Также класс должен иметь открытое свойство Count типа integer. При этом параметр, который передаётся методу Add, должен быть того же самого типа, что и параметр, возвращаемый из свойства Item, либо быть одной из баз такого же типа.
Если говорить о классах, реализующих ICollection, то для них сериализуемые значения извлекаются с помощью индексированного свойства Item, но не путём вызова GetEnumerator. Вдобавок к этому, свойства и открытые поля не сериализуются за исключением открытых полей, возвращающих другой класс коллекции (который реализует ICollection).
Сопоставление типа данных XSD
В документации W3C XML Schema Part 2: Типы данных прописаны простые типы данных, допускаемые в схему языка определения XML-схемы. Для большей части из них (например, decimal и int) в платформе .NET. предусмотрен соответствующий тип данных. Но для некоторых типов XML-данных соответствующий тип не предусмотрен (допустим для NMTOKEN). В этом случае, используя инструмент определения XML-схемы (Xsd.exe) для формирования классов из схемы, к члену строкового типа применяют специальный атрибут, а его свойство DataType задаётся в качестве имени типа XML-данных. Представьте, что схема содержит элемент «MyToken» с типом XML-данных NMTOKEN:
<XmlElement(DataType:="NMTOKEN")> _ Public MyToken As String [XmlElement(DataType = "NMTOKEN")] public string MyToken;
Аналогично мы действуем, создавая класс, который должен отвечать определённой XML-схеме (XSD). Мы применяем соответствующий атрибут, задавая его свойство DataType в качестве необходимого имени типа XML-данных.