Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Чтобы создать классы из схем, которые можно использовать с Windows Communication Foundation (WCF), используйте XsdDataContractImporter класс. В этом разделе описывается процесс и варианты.
Процесс импорта
Процесс импорта схемы начинается с XmlSchemaSet и создает объект CodeCompileUnit.
Это XmlSchemaSet
часть объектной модели схемы (SOM) .NET Framework, представляющей набор документов схемы языка описания схем XSD. Чтобы создать объект XmlSchemaSet
из набора документов XSD, каждый документ должен быть десериализован в объект XmlSchema (с помощью XmlSerializer), и затем эти объекты необходимо добавить в новый XmlSchemaSet
.
Это CodeCompileUnit
является частью объектной модели кода .NET Framework (CodeDOM), которая представляет код .NET Framework в абстрактной форме. Чтобы создать фактический код из CodeCompileUnit
класса, используйте подкласс CodeDomProvider класса, например CSharpCodeProvider класс или VBCodeProvider класс.
Импорт схемы
Создайте экземпляр объекта XsdDataContractImporter.
Необязательно. Передайте
CodeCompileUnit
в конструктор. Типы, создаваемые при импорте схемы, добавляются в этотCodeCompileUnit
экземпляр, а не начинают с пустогоCodeCompileUnit
.Необязательно. Вызовите один из CanImport методов. Метод определяет, является ли данная схема допустимым схемой контракта данных и может быть импортирована. Метод
CanImport
имеет те же перегрузки, чтоImport
и (следующий шаг).Вызовите один из перегруженных
Import
методов, например Import(XmlSchemaSet) метод.Самая простая перегрузка принимает
XmlSchemaSet
и импортирует все типы, включая анонимные типы, найденные в этом наборе схем. Другие перегрузки позволяют вам указать тип XSD или список типов для импорта (в виде элемента XmlQualifiedName или коллекции объектовXmlQualifiedName
). В этом случае импортируются только указанные типы. Перегрузка XmlSchemaElement принимает импортированное изXmlSchemaSet
определенный элемент, а также его связанный тип (независимо от того, является он анонимным или нет). Эта перегрузка возвращаетXmlQualifiedName
, которое представляет имя контракта данных типа, созданного для этого элемента.Несколько вызовов метода
Import
результатом является добавление нескольких элементов в один и тот жеCodeCompileUnit
. Тип не создается вCodeCompileUnit
, если он уже существует. ВызовитеImport
несколько раз на одном и том жеXsdDataContractImporter
, вместо того чтобы использовать несколько объектовXsdDataContractImporter
. Это рекомендуемый способ избежать создания повторяющихся типов.Замечание
Если во время импорта произойдет сбой,
CodeCompileUnit
будет находиться в непредсказуемом состоянии. ИспользованиеCodeCompileUnit
, полученного в результате неудачного импорта, может привести к уязвимостям системы безопасности.Доступ к
CodeCompileUnit
через свойство CodeCompileUnit.
Параметры импорта: настройка созданных типов
Вы можете задать свойство Options объекта XsdDataContractImporter с экземпляром класса ImportOptions для управления различными аспектами процесса импорта. Ряд параметров напрямую влияет на созданные типы.
Управление уровнем доступа (GenerateInternal или переключатель /internal)
Это соответствует переключателю /internal в средстве ServiceModel Metadata Utility Tool (Svcutil.exe).
Как правило, общедоступные типы создаются из схемы, с частными полями и соответствующими свойствами элемента общедоступных данных. Чтобы вместо этого создать внутренние типы, задайте свойству GenerateInternal значение true
.
В следующем примере показана схема, преобразованная во внутренний класс, когда GenerateInternal свойству присвоено значение true.
[DataContract]
internal partial class Vehicle : IExtensibleDataObject
{
private int yearField;
private string colorField;
[DataMember]
internal int year
{
get { return this.yearField; }
set { this.yearField = value; }
}
[DataMember]
internal string color
{
get { return this.colorField; }
set { this.colorField = value; }
}
private ExtensionDataObject extensionDataField;
public ExtensionDataObject ExtensionData
{
get { return this.extensionDataField; }
set { this.extensionDataField = value; }
}
}
Class Vehicle
Implements IExtensibleDataObject
Private yearField As Integer
Private colorField As String
<DataMember()> _
Friend Property year() As Integer
Get
Return Me.yearField
End Get
Set
Me.yearField = value
End Set
End Property
<DataMember()> _
Friend Property color() As String
Get
Return Me.colorField
End Get
Set
Me.colorField = value
End Set
End Property
Private extensionDataField As ExtensionDataObject
Public Property ExtensionData() As ExtensionDataObject _
Implements IExtensibleDataObject.ExtensionData
Get
Return Me.extensionDataField
End Get
Set(ByVal value As ExtensionDataObject)
Me.extensionDataField = value
End Set
End Property
End Class
Управление пространствами имен (пространства имен или переключатель /namespace)
Это соответствует переключателю /namespace в средстве Svcutil.exe
.
Как правило, типы, порожденные из схемы, находятся в пространствах имен .NET Framework, при этом каждое пространство имен XSD соответствует конкретному пространству имен .NET Framework в соответствии с сопоставлением, описанном в справочнике по схеме контракта данных. Вы можете настроить это сопоставление, преобразовав свойство Namespaces в Dictionary<TKey,TValue>. Если заданное пространство имен XSD найдено в словаре, соответствующее пространство имен .NET Framework также берется из словаря.
Например, рассмотрим следующую схему.
<xs:schema targetNamespace="http://schemas.contoso.com/carSchema">
<xs:complexType name="Vehicle">
<!-- details omitted... -->
</xs:complexType>
</xs:schema>
В следующем примере используется свойство Namespaces
, чтобы сопоставить пространство имен http://schemas.contoso.com/carSchema
с "Contoso.Cars".
XsdDataContractImporter importer = new XsdDataContractImporter();
importer.Options.Namespaces.Add(new KeyValuePair<string, string>("http://schemas.contoso.com/carSchema", "Contoso.Cars"));
Dim importer As New XsdDataContractImporter
importer.Options.Namespaces.Add(New KeyValuePair(Of String, String)("http://schemas.contoso.com/carSchema", "Contoso.Cars"))
Добавление SerializableAttribute (GenerateSerializable или /serializable)
Это соответствует параметру /serializable в инструменте Svcutil.exe
.
Иногда важно использовать типы, созданные из схемы, с помощью обработчиков сериализации среды выполнения .NET Framework. Это полезно при использовании типов для удалённого управления .NET Framework. Чтобы включить это, необходимо применить SerializableAttribute атрибут к созданным типам в дополнение к регулярному DataContractAttribute атрибуту. Атрибут создается автоматически, если для параметра импорта задано значение GenerateSerializable
.
В следующем примере показан классVehicle
, созданный с параметром импортаGenerateSerializable
, установленным вtrue
.
[DataContract]
[Serializable]
public partial class Vehicle : IExtensibleDataObject
{
// Code not shown.
public ExtensionDataObject ExtensionData
{
get
{
throw new Exception("The method or operation is not implemented.");
}
set
{
throw new Exception("The method or operation is not implemented.");
}
}
}
<DataContract(), Serializable()> _
Partial Class Vehicle
Implements IExtensibleDataObject
Private extensionDataField As ExtensionDataObject
' Code not shown.
Public Property ExtensionData() As ExtensionDataObject _
Implements IExtensibleDataObject.ExtensionData
Get
Return Me.extensionDataField
End Get
Set(ByVal value As ExtensionDataObject)
Me.extensionDataField = value
End Set
End Property
End Class
Добавление поддержки привязки данных (EnableDataBinding или переключателя /enableDataBinding)
Это соответствует переключателю /enableDataBinding в средстве Svcutil.exe.
Иногда может потребоваться привязать типы, созданные из схемы, к графическим компонентам пользовательского интерфейса, чтобы любое обновление экземпляров этих типов автоматически обновлялось.
XsdDataContractImporter
может создавать такие типы, которые реализуют интерфейс INotifyPropertyChanged таким образом, что любое изменение свойства вызывало событие. Если вы создаете типы для использования в среде программирования пользовательского интерфейса клиента, которая поддерживает этот интерфейс (например, Windows Presentation Foundation (WPF)), установите свойство EnableDataBinding в true
, чтобы включить эту функцию.
В следующем примере показано Vehicle
, как класс, созданный с набором EnableDataBindingtrue
.
[DataContract]
public partial class Vehicle : IExtensibleDataObject, INotifyPropertyChanged
{
private int yearField;
private string colorField;
[DataMember]
public int year
{
get { return this.yearField; }
set
{
if (this.yearField.Equals(value) != true)
{
this.yearField = value;
this.RaisePropertyChanged("year");
}
}
}
[DataMember]
public string color
{
get { return this.colorField; }
set
{
if (this.colorField.Equals(value) != true)
{
this.colorField = value;
this.RaisePropertyChanged("color");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler propertyChanged =
this.PropertyChanged;
if (propertyChanged != null)
{
propertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
private ExtensionDataObject extensionDataField;
public ExtensionDataObject ExtensionData
{
get { return this.extensionDataField; }
set { this.extensionDataField = value; }
}
}
Partial Class Vehicle
Implements IExtensibleDataObject, INotifyPropertyChanged
Private yearField As Integer
Private colorField As String
<DataMember()> _
Public Property year() As Integer
Get
Return Me.yearField
End Get
Set
If Me.yearField.Equals(value) <> True Then
Me.yearField = value
Me.RaisePropertyChanged("year")
End If
End Set
End Property
<DataMember()> _
Public Property color() As String
Get
Return Me.colorField
End Get
Set
If Me.colorField.Equals(value) <> True Then
Me.colorField = value
Me.RaisePropertyChanged("color")
End If
End Set
End Property
Public Event PropertyChanged As PropertyChangedEventHandler _
Implements INotifyPropertyChanged.PropertyChanged
Private Sub RaisePropertyChanged(ByVal propertyName As String)
RaiseEvent PropertyChanged(Me, _
New PropertyChangedEventArgs(propertyName))
End Sub
Private extensionDataField As ExtensionDataObject
Public Property ExtensionData() As ExtensionDataObject _
Implements IExtensibleDataObject.ExtensionData
Get
Return Me.extensionDataField
End Get
Set(ByVal value As ExtensionDataObject)
Me.extensionDataField = value
End Set
End Property
End Class
Параметры импорта: выбор типов коллекций
Два специальных шаблона в XML представляют коллекции элементов: списки элементов и связей между одним элементом и другим. Ниже приведен пример списка строк.
<People>
<person>Alice</person>
<person>Bob</person>
<person>Charlie</person>
</People>
Ниже приведен пример связи между строкой и целым числом (city name
и population
).
<Cities>
<city>
<name>Auburn</name>
<population>40000</population>
</city>
<city>
<name>Bellevue</name>
<population>80000</population>
</city>
<city>
<name>Cedar Creek</name>
<population>10000</population>
</city>
</Cities>
Замечание
Любая ассоциация также может считаться списком. Например, можно просмотреть предыдущую связь как список сложных city
объектов, которые могут иметь два поля (строковое поле и целочисленное поле). Оба шаблона имеют представление в схеме XSD. Нет способа различать список и связь, поэтому такие шаблоны всегда рассматриваются как списки, если в схеме отсутствует специальная заметка, относящаяся к WCF. Заметка указывает, что заданный шаблон представляет ассоциацию. Дополнительные сведения см. в справочнике по схеме контракта данных.
Как правило, список импортируется как контракт данных сбора, производный от универсального списка или массива .NET Framework, в зависимости от того, соответствует ли схема стандартному шаблону именования для коллекций. Более подробно описано в типах коллекций в контрактах данных. Ассоциации обычно импортируются либо как Dictionary<TKey,TValue>, либо как контракт данных коллекции, производный от объекта словаря. Например, рассмотрим следующую схему.
<xs:complexType name="Vehicle">
<xs:sequence>
<xs:element name="year" type="xs:int"/>
<xs:element name="color" type="xs:string"/>
<xs:element name="passengers" type="people"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="people">
<xs:sequence>
<xs:element name="person" type="xs:string" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
Это будет импортировано следующим образом (поля отображаются вместо свойств для удобочитаемости).
[DataContract]
public partial class Vehicle : IExtensibleDataObject
{
[DataMember] public int yearField;
[DataMember] public string colorField;
[DataMember] public people passengers;
// Other code not shown.
public ExtensionDataObject ExtensionData
{
get
{
throw new Exception("The method or operation is not implemented.");
}
set
{
throw new Exception("The method or operation is not implemented.");
}
}
}
[CollectionDataContract(ItemName = "person")]
public class people : List<string> { }
Public Partial Class Vehicle
Implements IExtensibleDataObject
<DataMember()> _
Public yearField As Integer
<DataMember()> _
Public colorField As String
<DataMember()> _
Public passengers As people
' Other code not shown.
Public Property ExtensionData() As ExtensionDataObject _
Implements IExtensibleDataObject.ExtensionData
Get
Throw New Exception("The method or operation is not implemented.")
End Get
Set
Throw New Exception("The method or operation is not implemented.")
End Set
End Property
End Class
<CollectionDataContract(ItemName:="person")> _
Public Class people
Inherits List(Of String)
End Class
Можно настроить типы коллекций, созданные для таких шаблонов схем. Например, вы можете создать коллекции, производные от класса BindingList<T> вместо класса List<T>, чтобы привязать тип к элементу списка и автоматически обновлять его при изменении содержимого коллекции. Для этого задайте свойству ReferencedCollectionTypesImportOptions класса список типов коллекций, которые будут использоваться (далее называется ссылочными типами). При импорте любой коллекции этот список ссылочных типов коллекций проверяется, а при обнаружении коллекции используется наиболее соответствующая коллекция. Соответствия сопоставляются только с типами, реализующими общий или не общий интерфейс IDictionary, а списки сравниваются с любым поддерживаемым типом коллекции.
Например, если ReferencedCollectionTypes для свойства задано BindingList<T>значение, people
тип в предыдущем примере создается следующим образом.
[CollectionDataContract(ItemName = "person")]
public class people : BindingList<string> { }
<CollectionDataContract(ItemName:="person")> _
Public Class people
Inherits BindingList(Of String)
Закрытый универсальный считается лучшим совпадением. Например, если типы BindingList(Of Integer)
и ArrayList передаются в коллекцию ссылочных типов, все списки целых чисел, найденные в схеме, импортируются в виде BindingList(Of Integer)
. Любые другие списки, например, List(Of String)
, импортируются в виде ArrayList
.
Если тип, реализующий универсальный IDictionary
интерфейс, добавляется в коллекцию ссылочных типов, его параметры типа должны быть полностью открытыми или полностью закрытыми.
Дубликаты не разрешены. Например, нельзя добавить к ссылочным типам как List(Of Integer)
, так и Collection(Of Integer)
. Это делает невозможным определить, какой должен использоваться при обнаружении списка целых чисел в схеме. Дубликаты будут обнаружены только в том случае, если в схеме есть тип, который выявляет проблему дублирования. Например, если импортированная схема не содержит списков целых чисел, то допускается наличие как List(Of Integer)
, так и Collection(Of Integer)
в коллекции ссылочных типов, но ни один из них не окажет никакого влияния.
Механизм ссылочных типов коллекций работает одинаково хорошо для коллекций сложных типов (включая коллекции других коллекций), а не только для коллекций примитивов.
Свойство ReferencedCollectionTypes
соответствует переключателю /collectionType в инструменте SvcUtil.exe. Обратите внимание, что для ссылки на несколько типов коллекций необходимо указать параметр /collectionType несколько раз. Если тип не находится в MsCorLib.dll, то его сборку необходимо также указать с помощью параметра /reference.
Параметры импорта: ссылка на существующие типы
Иногда типы в схеме соответствуют существующим типам .NET Framework и не требуется создавать эти типы с нуля. (Этот раздел относится только к типам неколлекции. Сведения о типах коллекций см. в предыдущем разделе.)
Например, у вас может быть стандартный тип контракта данных "Person", который всегда требуется использовать при представлении человека. Всякий раз, когда некоторые службы используют этот тип, и его схема отображается в метаданных службы, вы можете повторно использовать существующий Person
тип при импорте этой схемы вместо создания новой для каждой службы.
Для этого передайте список типов .NET Framework, которые необходимо повторно использовать в коллекцию ReferencedTypes , свойство возвращается в ImportOptions классе. Если у любого из этих типов есть имя контракта данных и пространство имен, соответствующее имени и пространству имен типа схемы, выполняется структурное сравнение. Если определено, что типы имеют соответствующие имена и структуры сопоставления, существующий тип .NET Framework повторно используется вместо создания нового. Если совпадает только имя, а не структура, будет вызвано исключение. Обратите внимание, что при ссылке на типы нет поддержки для ведения версий (например, добавления новых необязательных членов данных). Структуры должны точно соответствовать.
Разрешается добавление в коллекцию ссылочных типов нескольких типов с одинаковым именем контракта данных и пространством имен при условии, что типы схем с таким именем и пространством имен не импортируются. Это позволяет легко добавлять все типы из сборки в коллекцию, не беспокоясь о дубликатах для типов, которые на самом деле не присутствуют в схеме.
Свойство ReferencedTypes
соответствует переключателю /reference в определенных режимах работы инструмента Svcutil.exe.
Замечание
При использовании Svcutil.exe или (в Visual Studio) инструмента Добавить ссылку на службу все типы в MsCorLib.dll автоматически ссылаются.
Параметры импорта: импорт схемы non-DataContract в виде типов IXmlSerializable
Элемент XsdDataContractImporter поддерживает ограниченное подмножество схемы. Если в схеме присутствуют неподдерживаемые конструкции, например XML-атрибуты, попытка импорта заканчивается неудачей из-за исключения. Однако установка свойства ImportXmlType на true
расширяет диапазон поддерживаемых схем. Если задано значение true
, XsdDataContractImporter создаёт типы, реализующие интерфейс IXmlSerializable. Это обеспечивает прямой доступ к XML-представлению этих типов.
Рекомендации по проектированию
Возможно, трудно работать с слабо типизированным XML-представлением напрямую. Рекомендуется использовать альтернативный механизм сериализации, например XmlSerializer, для работы со схемами, несовместимыми с контрактами данных, строго типизированным образом. Дополнительные сведения см. в разделе "Использование класса XmlSerializer".
Некоторые конструкции схемы нельзя импортировать XsdDataContractImporter, даже если свойство ImportXmlType установлено на
true
. Опять же, рассмотрите использование XmlSerializer в таких случаях.Точные конструкции схемы, которые поддерживаются как при ImportXmlType, так и при
true
илиfalse
, описаны в Справочнике по схеме контракта данных.Схема созданных IXmlSerializable типов не сохраняет точность при импорте и экспорте. То есть экспорт схемы из созданных типов и импорт в качестве классов не возвращает исходную схему.
Можно объединить ImportXmlType параметр с ранее описанным параметром ReferencedTypes . Для типов, которые должны быть созданы в качестве IXmlSerializable реализаций, при использовании функции ReferencedTypes структурный контроль пропускается.
Опция ImportXmlType соответствует переключателю /importXmlTypes в инструменте Svcutil.exe.
Работа с автоматически генерированными типами IXmlSerializable
Созданные IXmlSerializable
типы содержат частное поле с именем nodesField, которое возвращает массив XmlNode объектов. При десериализации экземпляра такого типа можно получить доступ к XML-данным непосредственно через это поле с помощью объектной модели XML-документа. При сериализации экземпляра этого типа можно задать для этого поля нужные XML-данные и сериализовать его.
Достичь этого можно через реализацию IXmlSerializable
. В созданном IXmlSerializable
типе реализация ReadXml вызывает метод ReadNodes класса XmlSerializableServices. Этот метод является вспомогательным методом, который преобразует XML-код, предоставленный через XmlReader, в массив объектов XmlNode. Реализация WriteXml выполняет противоположность и преобразует массив XmlNode
объектов в последовательность вызовов XmlWriter . Это достигается с помощью WriteNodes метода.
Можно запустить процесс экспорта схемы на созданных IXmlSerializable
классах. Как уже говорилось ранее, вы не получите исходную схему обратно. Вместо этого вы получите стандартный тип XSD "anyType", который является подстановочным знаком для любого типа XSD.
Это достигается путем применения XmlSchemaProviderAttribute атрибута к созданным IXmlSerializable
классам и указания метода, который вызывает AddDefaultSchema метод для создания типа anyType.
Замечание
Тип XmlSerializableServices существует исключительно для поддержки этой конкретной функции. Не рекомендуется использовать для других целей.
Параметры импорта: дополнительные параметры
Ниже приведены дополнительные параметры импорта:
свойство CodeProvider. Укажите CodeDomProvider для использования при генерации кода для созданных классов. Механизм импорта пытается избежать использования функций, которые CodeDomProvider не поддерживает. CodeProvider Если параметр не задан, полный набор функций .NET Framework используется без ограничений.
свойство DataContractSurrogate. Реализацию IDataContractSurrogate можно указать с помощью этого свойства. IDataContractSurrogate настраивает процесс импорта. Дополнительные сведения см. в разделе «Суррогаты контрактов данных». По умолчанию суррогат не используется.