Import schématu pro generování tříd
Chcete-li vygenerovat třídy ze schémat, která lze použít se službou Windows Communication Foundation (WCF), použijte XsdDataContractImporter třídu. Toto téma popisuje proces a varianty.
Proces importu
Proces importu schématu začíná řetězcem XmlSchemaSet a vytvoří .CodeCompileUnit
Je XmlSchemaSet
součástí modelu SOM (Schema Object Model) rozhraní .NET Framework, který představuje sadu dokumentů schématu jazyka XSD (XML Schema Definition Language). Chcete-li vytvořit XmlSchemaSet
objekt ze sady dokumentů XSD, deserializovat každý dokument do objektu XmlSchema (pomocí XmlSerializer) a přidat tyto objekty do nového XmlSchemaSet
.
Je CodeCompileUnit
součástí modelu Code Document Object Model (CodeDOM) rozhraní .NET Framework, který představuje kód rozhraní .NET Framework abstraktním způsobem. Chcete-li vygenerovat skutečný kód z objektu CodeCompileUnit
, použijte podtřídu CodeDomProvider třídy, například CSharpCodeProvider třídu nebo VBCodeProvider třídu.
Import schématu
Vytvořte instanci XsdDataContractImporter.
Nepovinné. Předejte
CodeCompileUnit
konstruktor. Typy vygenerované během importu schématu se do tétoCodeCompileUnit
instance přidají místo toho, aby začínaly prázdnouCodeCompileUnit
hodnotou .Nepovinné. Volejte jednu z CanImport metod. Metoda určuje, zda dané schéma je platné schéma kontraktu dat a lze jej importovat. Metoda
CanImport
má stejné přetížení jakoImport
(další krok).Zavolejte jednu z přetížených
Import
metod, například metodu Import(XmlSchemaSet) .Nejjednodušší přetížení přebírá
XmlSchemaSet
a importuje všechny typy, včetně anonymních typů, nalezených v této sadě schématu. Další přetížení umožňují určit typ XSD nebo seznam typů, které se mají importovat (ve formě XmlQualifiedName objektuXmlQualifiedName
nebo kolekce objektů). V tomto případě se importují pouze zadané typy. Přetížení vezme XmlSchemaElement , že importuje určitý prvek zXmlSchemaSet
, stejně jako jeho přidružený typ (zda je anonymní nebo ne). Toto přetížení vrátí hodnotuXmlQualifiedName
, která představuje název datového kontraktu typu generovaného pro tento prvek.Více volání
Import
metody vede k přidání více položek do stejnéhoCodeCompileUnit
. Typ není vygenerován vCodeCompileUnit
případě, že již existuje. Místo použití více objektů volejteImport
vícekrát na stejnéXsdDataContractImporter
místo použití víceXsdDataContractImporter
objektů. Toto je doporučený způsob, jak se vyhnout generování duplicitních typů.Poznámka:
Pokud během importu dojde k selhání,
CodeCompileUnit
bude stav nepředvídatelný. Použití výsledkuCodeCompileUnit
z neúspěšného importu by vás mohlo vystavit ohrožením zabezpečení.Přístup k
CodeCompileUnit
CodeCompileUnit vlastnosti.
Možnosti importu: Přizpůsobení vygenerovaných typů
Vlastnost třídy XsdDataContractImporter můžete nastavit Options na instanci ImportOptions třídy, která řídí různé aspekty procesu importu. Řada možností přímo ovlivňuje typy, které se generují.
Řízení úrovně přístupu (GenerateInternal nebo /internal switch)
To odpovídá /internal přepínač v nástroji ServiceModel Metadata Utility (Svcutil.exe).
Veřejné typy se obvykle generují ze schématu s privátními poli a odpovídajícími vlastnostmi veřejného datového členu. Chcete-li místo toho generovat interní typy, nastavte GenerateInternal vlastnost na true
.
Následující příklad ukazuje schéma transformované na interní třídu, když GenerateInternal je vlastnost nastavena na 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
Řízení oborů názvů (obory názvů nebo přepínač /namespace)
To odpovídá přepínači /namespace v nástroji Svcutil.exe
.
Obvykle se typy generované ze schématu generují do oborů názvů rozhraní .NET Framework, přičemž každý obor názvů XSD odpovídá určitému oboru názvů rozhraní .NET Framework podle mapování popsaného v odkazu schématu kontraktu dat. Toto mapování Namespaces můžete přizpůsobit vlastností na hodnotu Dictionary<TKey,TValue>. Pokud se daný obor názvů XSD nachází ve slovníku, odpovídající obor názvů rozhraní .NET Framework se přebírá také z vašeho slovníku.
Představte si například následující schéma.
<xs:schema targetNamespace="http://schemas.contoso.com/carSchema">
<xs:complexType name="Vehicle">
<!-- details omitted... -->
</xs:complexType>
</xs:schema>
Následující příklad používá Namespaces
vlastnost k mapování http://schemas.contoso.com/carSchema
oboru názvů na 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"))
Přidání SerializableAttribute (GenerateSerializable nebo /serializable switch)
To odpovídá přepínači /serializable v nástroji Svcutil.exe
.
Někdy je důležité, aby typy generované ze schématu byly použitelné s moduly serializace modulu runtime rozhraní .NET Framework. To je užitečné při použití typů pro vzdálené komunikace rozhraní .NET Framework. Chcete-li to povolit, je nutné SerializableAttribute použít atribut na vygenerované typy kromě běžného DataContractAttribute atributu. Atribut se vygeneruje automaticky, pokud je možnost importu GenerateSerializable
nastavena na true
.
Následující příklad ukazuje Vehicle
třídu vygenerovanou s možností importu nastavenou GenerateSerializable
na 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
Přidání podpory datových vazeb (EnableDataBinding nebo přepínač /enableDataBinding)
To odpovídá přepínači /enableDataBinding v nástroji Svcutil.exe.
Někdy můžete chtít svázat typy vygenerované ze schématu na grafické součásti uživatelského rozhraní, aby všechny aktualizace instancí těchto typů automaticky aktualizovaly uživatelské rozhraní. XsdDataContractImporter
Můžou generovat typy, které implementují INotifyPropertyChanged rozhraní takovým způsobem, že jakákoli změna vlastnosti aktivuje událost. Pokud generujete typy pro použití s programovacím prostředím klientského uživatelského rozhraní, které podporuje toto rozhraní (například Windows Presentation Foundation (WPF)), nastavte EnableDataBinding vlastnost na true
povolení této funkce.
Následující příklad ukazuje Vehicle
třídu vygenerovanou se EnableDataBinding sadou na true
.
[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
Možnosti importu: Volba typů kolekcí
Dva speciální vzory v jazyce XML představují kolekce položek: seznamy položek a přidružení mezi jednou položkou a druhou. Následuje příklad seznamu řetězců.
<People>
<person>Alice</person>
<person>Bob</person>
<person>Charlie</person>
</People>
Následuje příklad přidružení mezi řetězcem a celé číslo (city name
a 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>
Poznámka:
Všechna přidružení by se také mohla považovat za seznam. Předchozí přidružení můžete například zobrazit jako seznam složitých city
objektů, u kterých se stane, že mají dvě pole (řetězcové pole a celé číslo). Oba vzory mají reprezentaci ve schématu XSD. Neexistuje způsob, jak rozlišovat mezi seznamem a přidružením, takže takové vzory jsou vždy považovány za seznamy, pokud není ve schématu přítomna zvláštní poznámka specifická pro WCF. Poznámka označuje, že daný vzor představuje přidružení. Další informace naleznete v tématu Referenční informace ke schématu kontraktu dat.
Obvykle se seznam importuje jako kontrakt dat kolekce, který je odvozený z obecného seznamu nebo jako pole rozhraní .NET Framework, v závislosti na tom, zda schéma dodržuje standardní vzor pojmenování pro kolekce. Toto je podrobněji popsáno v typech kolekcí v kontraktech dat. Přidružení se obvykle importují jako Dictionary<TKey,TValue> kontrakt dat kolekce, který je odvozený z objektu slovníku. Představte si například následující schéma.
<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>
Tato možnost by se naimportovala následujícím způsobem (pole se místo vlastností pro čitelnost zobrazují).
[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
Typy kolekcí vygenerované pro takové vzory schématu je možné přizpůsobit. Můžete například chtít vygenerovat kolekce odvozené od BindingList<T> třídy místo List<T> třídy, aby bylo možné svázat typ se seznamem a nechat je automaticky aktualizovat při změně obsahu kolekce. Chcete-li to provést, nastavte ReferencedCollectionTypes vlastnost ImportOptions třídy na seznam typů kolekce, které se mají použít (dále označované jako odkazované typy). Při importu jakékoli kolekce se tento seznam odkazovaných typů kolekcí zkontroluje a použije se nejvhodnější kolekce, pokud se najde. Přidružení se shodují pouze s typy, které implementují obecné nebo negenerické IDictionary rozhraní, zatímco seznamy se shodují s jakýmkoli podporovaným typem kolekce.
Pokud ReferencedCollectionTypes je například vlastnost nastavena na BindingList<T>, people
typ v předchozím příkladu je generován následujícím způsobem.
[CollectionDataContract(ItemName = "person")]
public class people : BindingList<string> { }
<CollectionDataContract(ItemName:="person")> _
Public Class people
Inherits BindingList(Of String)
Uzavřený obecný se považuje za nejlepší shodu. Například pokud jsou typy BindingList(Of Integer)
a ArrayList jsou předány do kolekce odkazovaných typů, všechny seznamy celých čísel nalezených ve schématu BindingList(Of Integer)
jsou importovány jako . Všechny ostatní seznamy, například List(Of String)
, jsou importovány jako ArrayList
.
Pokud je do kolekce odkazovaných typů přidán typ, který implementuje obecné IDictionary
rozhraní, musí být parametry typu buď plně otevřené, nebo plně uzavřeny.
Duplicitní položky nejsou povoleny. Například do odkazovaných typů nemůžete přidat ani List(Of Integer)
a Collection(Of Integer)
. To by znemožnilo určit, které by se mělo použít, když se ve schématu nachází seznam celých čísel. Duplicity budou zjištěny pouze v případě, že existuje typ ve schématu, který zveřejňuje problém s duplicitami. Pokud například importované schéma neobsahuje seznamy celých čísel, je povoleno mít v List(Of Integer)
kolekci odkazovaných typů i Collection(Of Integer)
v kolekci odkazovaných typů žádný vliv.
Mechanismus odkazovaných typů kolekcí funguje stejně dobře pro kolekce komplexních typů (včetně kolekcí jiných kolekcí), a ne jen pro kolekce primitiv.
ReferencedCollectionTypes
Vlastnost odpovídá přepínač /collectionType v nástroji SvcUtil.exe. Upozorňujeme, že pokud chcete odkazovat na více typů kolekcí, musí být přepínač /collectionType zadán vícekrát. Pokud typ není v MsCorLib.dll, musí být jeho sestavení odkazováno také pomocí přepínače /reference .
Možnosti importu: Odkazování na existující typy
Někdy typy ve schématu odpovídají existujícím typům rozhraní .NET Framework a není nutné tyto typy generovat úplně od začátku. (Tato část se vztahuje pouze na typy bez kóty. Typy kolekcí najdete v předchozí části.)
Můžete mít například standardní datový typ "Osoba", který chcete vždy použít při reprezentaci osoby. Kdykoli některá služba používá tento typ a jeho schéma se zobrazí v metadatech služby, můžete při importu tohoto schématu místo generování nového pro každou službu použít existující Person
typ.
Uděláte to tak, že předáte seznam typů rozhraní .NET Framework, které chcete znovu použít do kolekce, ReferencedTypes která vlastnost vrátí pro ImportOptions třídu. Pokud některý z těchto typů má název datového kontraktu a obor názvů, který odpovídá názvu a oboru názvů typu schématu, provede se strukturální porovnání. Pokud se zjistí, že typy mají odpovídající názvy i odpovídající struktury, stávající typ rozhraní .NET Framework se znovu použije místo generování nové. Pokud se název shoduje pouze se strukturou, vyvolá se výjimka. Všimněte si, že při odkazování na typy (například přidání nových nepovinných datových členů) není povolená správa verzí. Struktury se musí přesně shodovat.
Do kolekce odkazovaných typů je možné přidat více typů se stejným názvem kontraktu dat a oborem názvů, pokud se s tímto názvem a oborem názvů neimportují žádné typy schématu. To vám umožní snadno přidat všechny typy v sestavení do kolekce, aniž byste se museli starat o duplicity pro typy, které ve skutečnosti nedochází ve schématu.
Vlastnost ReferencedTypes
odpovídá přepínači /reference v určitých režimech provozu nástroje Svcutil.exe.
Poznámka:
Při použití Svcutil.exe nebo (v sadě Visual Studio) nástroje Add Service Reference se automaticky odkazují na všechny typy v MsCorLib.dll.
Možnosti importu: Import schématu non-DataContract jako typy IXmlSerializable
Podporuje XsdDataContractImporter omezenou podmnožinu schématu. Pokud existují nepodporované konstrukce schématu (například atributy XML), pokus o import selže s výjimkou. Nastavení ImportXmlType vlastnosti pro true
rozšíření rozsahu podporovaného schématu. Při nastavení na true
, generuje XsdDataContractImporter typy, které implementují IXmlSerializable rozhraní. To umožňuje přímý přístup k reprezentaci XML těchto typů.
Na co dát pozor při navrhování
Může být obtížné pracovat přímo se slabě napsanou reprezentací XML. Zvažte použití alternativního serializačního XmlSerializermodulu, jako je například , pro práci se schématem nekompatibilním s datovými kontrakty silným typem. Další informace naleznete v tématu Použití Třídy XmlSerializer.
Některé konstrukce schématu nelze importovat XsdDataContractImporter , i když ImportXmlType je vlastnost nastavena na
true
. Opět zvažte použití XmlSerializer těchto případů.Přesné konstrukce schématu, které jsou podporovány, pokud ImportXmlType je
true
nebofalse
jsou popsány v odkazu schématu kontraktu dat.Schéma vygenerovaných IXmlSerializable typů si při importu a exportu nezachovává věrnost. To znamená, že export schématu z vygenerovaných typů a importování jako třídy nevrací původní schéma.
Možnost je možné zkombinovat ImportXmlType s dříve popsanou ReferencedTypes možností. U typů, které je potřeba vygenerovat jako IXmlSerializable implementace, se strukturální kontrola při použití ReferencedTypes funkce přeskočí.
Možnost ImportXmlType odpovídá přepínači /importXmlTypes v nástroji Svcutil.exe.
Práce s vygenerovanými typy IXmlSerializable
Vygenerované IXmlSerializable
typy obsahují privátní pole s názvem nodesField, které vrací pole XmlNode objektů. Při deserializaci instance takového typu můžete přistupovat k datům XML přímo prostřednictvím tohoto pole pomocí objektového modelu dokumentu XML. Při serializaci instance tohoto typu můžete toto pole nastavit na požadovaná data XML a bude serializován.
Toho se dosahuje prostřednictvím IXmlSerializable
implementace. Ve vygenerovaném IXmlSerializable
typu ReadXml implementace volá ReadNodes metodu XmlSerializableServices třídy. Tato metoda je pomocná metoda, která převádí XML poskytované prostřednictvím XmlReader pole XmlNode objektů. Implementace WriteXml provede opak a převede pole XmlNode
objektů na posloupnost XmlWriter volání. Toho se dosahuje pomocí WriteNodes metody.
Proces exportu schématu je možné spustit ve vygenerovaných IXmlSerializable
třídách. Jak už bylo uvedeno dříve, původní schéma se zpět nedostane. Místo toho získáte standardní typ XSD typu anyType, což je zástupný znak pro libovolný typ XSD.
Toho lze dosáhnout použitím atributu XmlSchemaProviderAttribute na vygenerované IXmlSerializable
třídy a určení metody, která volá AddDefaultSchema metodu pro vygenerování typu anyType.
Poznámka:
Typ XmlSerializableServices existuje výhradně pro podporu této konkrétní funkce. Nedoporučuje se používat pro žádný jiný účel.
Možnosti importu: Upřesnit možnosti
Níže jsou uvedené pokročilé možnosti importu:
CodeProvider Vlastnost. CodeDomProvider Zadejte, který se má použít k vygenerování kódu pro vygenerované třídy. Mechanismus importu se pokusí vyhnout funkcím, které CodeDomProvider nepodporuje. Pokud není CodeProvider nastavená, použije se úplná sada funkcí rozhraní .NET Framework bez omezení.
DataContractSurrogate Vlastnost. Pomocí IDataContractSurrogate této vlastnosti lze zadat implementaci. Proces IDataContractSurrogate importu přizpůsobí. Další informace naleznete v tématu Náhradní smlouvy dat. Ve výchozím nastavení se nepoužívá žádná náhradní položka.