Sdílet prostřednictvím


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

  1. Vytvořte instanci XsdDataContractImporter.

  2. Nepovinné. Předejte CodeCompileUnit konstruktor. Typy vygenerované během importu schématu se do této CodeCompileUnit instance přidají místo toho, aby začínaly prázdnou CodeCompileUnithodnotou .

  3. 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í jako Import (další krok).

  4. 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 objektu XmlQualifiedName nebo kolekce objektů). V tomto případě se importují pouze zadané typy. Přetížení vezme XmlSchemaElement , že importuje určitý prvek z XmlSchemaSet, stejně jako jeho přidružený typ (zda je anonymní nebo ne). Toto přetížení vrátí hodnotu XmlQualifiedName, 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ého CodeCompileUnit. Typ není vygenerován v CodeCompileUnit případě, že již existuje. Místo použití více objektů volejte Import vícekrát na stejné XsdDataContractImporter místo použití více XsdDataContractImporter 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ýsledku CodeCompileUnit z neúspěšného importu by vás mohlo vystavit ohrožením zabezpečení.

  5. Přístup k CodeCompileUnitCodeCompileUnit 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 nebo false 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:

Viz také