Freigeben über


Importieren von Schemas zum Generieren von Klassen

Um aus Schemas Klassen zu generieren, die mit Windows Communication Foundation (WCF) genutzt werden können, verwenden Sie die XsdDataContractImporter-Klasse. In diesem Thema werden der Prozess und die Variationen beschrieben.

Der Importprozess

Der Schemaimportprozess beginnt mit XmlSchemaSet und erzeugt ein CodeCompileUnit-Element.

XmlSchemaSet ist Teil des SOM (Schemaobjektmodell) von .NET Framework, das eine Gruppe von XSD-Schemadokumenten (XML Schema Definition Language) darstellt. Um ein XmlSchemaSet-Objekt aus einer Gruppe von XSD-Dokumenten zu erstellen, deserialisieren Sie die einzelnen Dokumente in ein XmlSchema-Objekt (mithilfe von XmlSerializer) und fügen diese Objekte einem neuen XmlSchemaSet-Element hinzu.

CodeCompileUnit ist Teil des CodeDOM (Code-Dokumentobjektmodell) von .NET Framework, das den .NET Framework-Code abstrakt darstellt. Um den eigentlichen Code aus einer CodeCompileUnit zu generieren, verwenden Sie eine Unterklasse der CodeDomProvider-Klasse, zum Beispiel die CSharpCodeProvider- oder VBCodeProvider-Klasse.

So importieren Sie ein Schema

  1. Erstellen Sie eine Instanz von XsdDataContractImporter.

  2. Optional. Übergeben Sie im Konstruktor eine CodeCompileUnit. Die während des Schemaimports generierten Typen werden dieser CodeCompileUnit-Instanz hinzugefügt. Es wird keine leere CodeCompileUnit verwendet.

  3. Optional. Rufen Sie eine der CanImport-Methoden auf. Die Methode bestimmt, ob es sich beim jeweiligen Schema um ein gültiges Datenvertragsschema handelt und ob es importiert werden kann. Die CanImport-Methode verfügt über die gleichen Überladungen wie Import (der nächste Schritt).

  4. Rufen Sie eine der überladenen Import-Methoden auf, zum Beispiel die Import-Methode.

    Bei der einfachsten Überladung wird ein XmlSchemaSet verwendet, und es werden alle Typen importiert, die im Schemasatz enthalten sind, einschließlich anonyme Typen. Bei anderen Überladungen können Sie den XSD-Typ oder eine Liste der Typen angeben, die importiert werden sollen (in Form eines XmlQualifiedName-Objekts oder einer Auflistung mit XmlQualifiedName-Objekten). In diesem Fall werden nur die angegebenen Typen importiert. Eine Überladung verwendet ein XmlSchemaElement, das ein bestimmtes Element aus dem XmlSchemaSet importiert, einschließlich des dazugehörigen Typs (anonym oder nicht anonym). Diese Überladung gibt einen XmlQualifiedName zurück, der für den Datenvertragsnamen des Typs steht, der für dieses Element generiert wurde.

    Mehrere Aufrufe der Import-Methode führen dazu, dass mehrere Elemente derselben CodeCompileUnit hinzugefügt werden. Ein Typ wird nicht für die CodeCompileUnit generiert, wenn dieser darin bereits vorhanden ist. Rufen Sie Import für einen XsdDataContractImporter mehrfach auf, anstatt mehrere XsdDataContractImporter-Objekte zu verwenden. Dies ist die empfohlene Möglichkeit, um die Generierung von doppelten Typen zu vermeiden.

    Tipp

    Wenn beim Importieren ein Fehler auftritt, befindet sich die CodeCompileUnit in einem unvorhersehbaren Zustand. Wenn Sie eine CodeCompileUnit verwenden, die aus einem fehlgeschlagenen Import stammt, kann Sie dies ggf. anfällig für Sicherheitslücken machen.

  5. Greifen Sie auf die CodeCompileUnit mithilfe der CodeCompileUnit-Eigenschaft zu.

Importoptionen: Anpassen der generierten Typen

Sie können die Options-Eigenschaft von XsdDataContractImporter auf eine Instanz der ImportOptions-Klasse festlegen, um verschiedene Aspekte des Importprozesses zu steuern. Verschiedene Optionen wirken sich direkt auf die generierten Typen aus.

Steuern der Zugriffsebene (GenerateInternal oder der Schalter "/internal")

Dies entspricht dem Schalter /internal im ServiceModel Metadata Utility Tool (Svcutil.exe).

Normalerweise werden öffentliche Typen aus Schemas generiert, indem private Felder und passende Eigenschaften öffentlicher Datenmember verwendet werden. Wenn Sie stattdessen interne Typen generieren möchten, legen Sie die GenerateInternal-Eigenschaft auf true fest.

Das folgende Beispiel zeigt ein Schema, das in eine interne Klasse umgewandelt wird, wenn die GenerateInternal-Eigenschaft auf true festgelegt ist.

Steuern von Namespaces (Namespaces oder der Schalter "/namespace")

Dies entspricht dem Schalter /namespace im Tool Svcutil.exe.

Normalerweise werden aus Schemas generierte Typen als .NET Framework-Namespaces generiert, wobei die XSD-Namespaces jeweils einem bestimmten .NET Framework-Namespace entsprechen. Diese Zuordnung ist unter Datenvertrags-Schemareferenz beschrieben. Sie können diese Zuordnung mithilfe der Namespaces-Eigenschaft eines Dictionary anpassen. Wenn ein bestimmter XSD-Namespace im Wörterbuch enthalten ist, wird auch der entsprechende .NET Framework-Namespace aus Ihrem Wörterbuch verwendet.

Betrachten Sie zum Beispiel das folgende Schema:

Im folgenden Beispiel wird die Namespaces-Eigenschaft verwendet, um den http://schemas.contoso.com/carSchema-Namespace "Contoso.Cars" zuzuordnen.

Hinzufügen von SerializableAttribute (GenerateSerializable oder der Schalter "/serializable")

Dies entspricht dem Schalter /serializable im Tool Svcutil.exe.

In einigen Fällen kann es wichtig sein, dass die aus dem Schema generierten Typen mit .NET Framework-Laufzeitserialisierungsmodulen verwendet werden können (zum Beispiel mit den Klassen BinaryFormatter und SoapFormatter). Dies ist hilfreich, wenn Sie Typen für das .NET Framework-Remoting nutzen. Um dies zu aktivieren, müssen Sie das SerializableAttribute-Attribut zusätzlich zum normalen DataContractAttribute-Attribut auf die generierten Typen anwenden. Das Attribut wird automatisch generiert, wenn die Importoption GenerateSerializable auf true festgelegt ist.

Das folgende Beispiel zeigt die Vehicle-Klasse, bei deren Generierung die Importoption GenerateSerializable auf true festgelegt ist.

Hinzufügen von Datenbindungsunterstützung (EnableDataBinding oder der Schalter "/enableDataBinding")

Dies entspricht dem Schalter /enableDataBinding im Tool Svcutil.exe.

In einigen Fällen kann es ratsam sein, die aus dem Schema generierten Typen an Komponenten der grafischen Benutzeroberfläche zu binden, damit die Aktualisierungen der Instanzen dieser Typen automatisch auf der Benutzeroberfläche widergespiegelt werden. Der XsdDataContractImporter kann Typen generieren, die die INotifyPropertyChanged-Schnittstelle so implementieren, dass alle Änderungen von Eigenschaften ein Ereignis auslösen. Wenn Sie Typen für die Verwendung mit einer Programmierumgebung für die Clientbenutzeroberfläche generieren, die diese Schnittstelle unterstützt (zum Beispiel Windows Presentation Foundation (WPF)), legen Sie die EnableDataBinding-Eigenschaft zum Aktivieren dieses Features auf true fest.

Das folgende Beispiel zeigt die Vehicle-Klasse, bei deren Generierung EnableDataBinding auf true festgelegt ist.

Importoptionen: Wählen von Auflistungstypen

Zwei spezielle XML-Muster stellen Auflistungen von Elementen dar: Listen mit Elementen und Zuordnungen zwischen einem Element und einem anderen. Unten ist ein Beispiel für eine Liste mit Zeichenfolgen angegeben.

Das folgende Beispiel zeigt eine Zuordnung zwischen einer Zeichenfolge und einer Ganzzahl (city name und population).

Tipp

Jede Zuordnung kann auch als Liste angesehen werden. Sie können die oben angegebene Zuordnung zum Beispiel als Liste mit komplexen city-Objekten ansehen, die zwei Felder aufweisen (ein Zeichenfolgenfeld und ein Ganzzahlfeld). Beide Muster verfügen im XSD-Schema über eine Darstellung. Es ist nicht möglich, zwischen einer Liste und einer Zuordnung zu unterscheiden. Aus diesem Grund werden Muster dieser Art immer wie Listen behandelt, es sei denn, das Schema enthält eine bestimmte WCF-spezifische Anmerkung. Die Anmerkung gibt an, dass ein bestimmtes Muster eine Zuordnung darstellt. Weitere Informationen finden Sie unter Datenvertrags-Schemareferenz.

In der Regel wird eine Liste als Auflistungsdatenvertrag importiert, der von einer generischen Liste oder einem .NET Framework-Array abgeleitet ist. Dies hängt davon ab, ob das Schema das standardmäßige Namensmuster für Auflistungen verwendet. Ausführlichere Informationen hierzu finden Sie unter Sammlungstypen in Datenverträgen. Zuordnungen werden normalerweise entweder als Dictionary oder als Auflistungsdatenvertrag importiert, der vom Wörterbuchobjekt abgeleitet ist. Betrachten Sie zum Beispiel das folgende Schema:

Der Import wird hierbei wie folgt durchgeführt (aus Gründen der besseren Lesbarkeit werden anstelle von Eigenschaften Felder angezeigt).

Es ist möglich, die Auflistungstypen anzupassen, die für Schemamuster dieser Art generiert werden. Es kann beispielsweise sein, dass Sie Auflistungen generieren, die von BindingList abgeleitet sind, anstatt von der List-Klasse, um den Typ an ein Listenfeld zu binden und automatisch aktualisieren zu lassen, wenn sich der Inhalt der Auflistung ändert. Legen Sie dazu die ReferencedCollectionTypes-Eigenschaft der ImportOptions-Klasse auf eine Liste mit zu verwendenden Auflistungstypen (im Weiteren als referenzierte Typen bezeichnet) fest. Beim Importieren von Auflistungen wird diese Liste mit Verweisen zu Auflistungstypen durchsucht und die Auflistung mit der höchsten Übereinstimmung verwendet, falls vorhanden. Es ergeben sich bei Zuordnungen nur für Typen Übereinstimmungen, die entweder die generische oder die nicht generische IDictionary-Schnittstelle implementieren, während sich bei Listen für alle unterstützten Auflistungstypen Übereinstimmungen ergeben können.

Wenn die ReferencedCollectionTypes-Eigenschaft zum Beispiel auf eine BindingList festgelegt ist, wird der people-Typ aus dem vorherigen Beispiel wie folgt generiert.

Ein geschlossener generischer Typ wird als beste Übereinstimmung betrachtet. Wenn beispielsweise die Typen BindingList(Of Integer) und ArrayList an die Auflistung der referenzierten Typen übergeben werden, werden alle Listen mit Ganzzahlen, die im Schema enthalten sind, als BindingList(Of Integer) importiert. Alle anderen Listen, zum Beispiel List(Of String), werden als ArrayList importiert.

Wenn ein Typ, der die generische IDictionary-Schnittstelle implementiert, der Auflistung der referenzierten Typen hinzugefügt wird, müssen ihre Typparameter entweder vollständig offen oder vollständig geschlossen sein.

Duplikate sind nicht zulässig. Zum Beispiel können Sie den referenzierten Typen nicht sowohl eine List(Of Integer) als auch eine Collection(Of Integer) hinzufügen. In diesem Fall wäre es unmöglich zu bestimmen, welches Element verwendet werden soll, wenn im Schema eine Liste mit Ganzzahlen gefunden wird. Duplikate werden nur erkannt, wenn es einen Typ im Schema gibt, der das Duplikatproblem offenlegt. Wenn das importierte Schema zum Beispiel keine Listen mit Ganzzahlen enthält, ist es zulässig, sowohl die List(Of Integer) als auch die Collection(Of Integer) in der Auflistung mit den referenzierten Typen zu verwenden, aber beide haben keine Auswirkung.

Der Mechanismus mit den referenzierten Auflistungstypen funktioniert ebenso gut für Auflistungen mit komplexen Typen (einschließlich Auflistungen anderer Auflistungen), nicht nur für Auflistungen von primitiven Typen.

Die ReferencedCollectionTypes-Eigenschaft entspricht dem Schalter /collectionType im Tool SvcUtil.exe. Beachten Sie, dass der Schalter /collectionType mehrmals angegeben werden muss, um auf mehrere Auflistungstypen verweisen zu können. Wenn der Typ nicht in der Datei MsCorLib.dll enthalten ist, muss auf die dazugehörige Assembly ebenfalls mithilfe des Schalters /reference verwiesen werden.

Importoptionen: Verweisen auf vorhandene Typen

In einigen Fällen entsprechen Typen im Schema vorhandenen .NET Framework-Typen, und es ist nicht erforderlich, diese Typen ganz neu zu generieren. (Dieser Abschnitt gilt nur für Typen, bei denen es sich nicht um Auflistungstypen handelt. Auflistungstypen finden Sie im vorherigen Abschnitt.)

Es kann zum Beispiel sein, dass Sie über einen standardmäßigen unternehmensweiten Datenvertragstyp "Person" verfügen, der beim Darstellen einer Person immer verwendet werden soll. Jedes Mal, wenn ein Dienst diesen Typ verwendet und das dazugehörige Schema in den Dienstmetadaten erscheint, sollten Sie den vorhandenen Person-Typ beim Importieren des Schemas wiederverwenden, anstatt für jeden Dienst ein neues Schema zu erstellen.

Übergeben Sie dazu eine Liste mit .NET Framework-Typen, die Sie wiederverwenden möchten, an die Auflistung, die die ReferencedTypes-Eigenschaft für die ImportOptions-Klasse zurückgibt. Falls einige dieser Typen einen Datenvertragsnamen und Namespace aufweisen, der mit dem Namen und Namespace eines Schematyps übereinstimmt, wird ein Strukturvergleich durchgeführt. Wenn ermittelt wird, dass die Typen über übereinstimmende Namen und Strukturen verfügen, wird der vorhandene .NET Framework-Typ wiederverwendet und kein neuer Typ generiert. Wenn nur der Name übereinstimmt, aber nicht die Struktur, wird eine Ausnahme ausgelöst. Beachten Sie, dass beim Verweisen auf Typen (zum Beispiel beim Hinzufügen von neuen optionalen Datenmembern) kein Spielraum für unterschiedliche Versionen besteht. Die Strukturen müssen genau übereinstimmen.

Es ist zulässig, der Auflistung der referenzierten Typen mehrere Typen mit demselben Datenvertragsnamen und Namespace hinzuzufügen, solange keine Schematypen mit diesem Namen und Namespace importiert werden. So können Sie der Auflistung alle in einer Assembly enthaltenen Typen auf einfache Weise hinzufügen, ohne sich um Duplikate von Typen kümmern zu müssen, die im Schema eigentlich nicht vorkommen.

Die ReferencedTypes-Eigenschaft entspricht dem Schalter /reference bei bestimmten Verwendungsarten des Tools Svcutil.exe.

Tipp

Wenn Sie die Tools Svcutil.exe oder (in Visual Studio) Dienstverweis hinzufügen verwenden, sind alle Typen der Datei MsCorLib.dll automatisch referenziert.

Importoptionen: Importieren von Nicht-DataContract-Schemas als IXmlSerializable-Typen

Der XsdDataContractImporter unterstützt eine beschränkte Teilmenge des Schemas. Wenn nicht unterstützte Schemakonstrukte vorhanden sind (zum Beispiel XML-Attribute), schlägt der Importversuch mit einer Ausnahme fehl. Das Festlegen der ImportXmlType-Eigenschaft auf true erweitert jedoch den unterstützten Schemabereich. Wenn true festgelegt ist, generiert der XsdDataContractImporter Typen, die die IXmlSerializable-Schnittstelle implementieren. Auf diese Weise wird der Direktzugriff auf die XML-Darstellung dieser Typen aktiviert.

Entwurfsüberlegungen

  • Es kann schwierig sein, direkt mit der schwach typisierten XML-Darstellung zu arbeiten. Sie sollten erwägen, ein alternatives Serialisierungsmodul zu verwenden, beispielsweise XmlSerializer, um mit Schemas arbeiten zu können, die mit stark typisierten Datenverträgen nicht kompatibel sind. Weitere Informationen finden Sie unter Verwenden der XmlSerializer-Klasse.
  • Einige Schemakonstrukte können über XsdDataContractImporter nicht importiert werden. Dies ist auch dann nicht möglich, wenn die ImportXmlType-Eigenschaft auf true festgelegt ist. Sie sollten auch hierfür erwägen, XmlSerializer zu verwenden.
  • Die genauen Schemakonstrukte, die unterstützt werden, wenn ImportXmlType den Wert true oder false hat, sind unter Datenvertrags-Schemareferenz beschrieben.
  • Schemas für generierte IXmlSerializable-Typen behalten beim Importieren und Exportieren ihre Originaltreue nicht bei. Wenn Sie das Schema also aus den generierten Typen exportieren und jeweils als Klasse importieren, wird nicht das Originalschema zurückgegeben.

Es ist möglich, die ImportXmlType-Option mit der oben beschriebenen ReferencedTypes-Option zu kombinieren. Für Typen, die als IXmlSerializable-Implementierungen generiert werden müssen, wird beim Verwenden des ReferencedTypes-Features die Strukturprüfung übersprungen.

Die ImportXmlType-Option entspricht dem Schalter /importXmlTypes im Tool Svcutil.exe.

Arbeiten mit generierten IXmlSerializable-Typen

Die generierten IXmlSerializable-Typen enthalten ein privates Feld mit der Bezeichnung "nodesField", das ein Array mit XmlNode-Objekten zurückgibt. Beim Deserialisieren der Instanz eines Typs dieser Art können Sie auf die XML-Daten direkt über dieses Feld zugreifen, indem Sie das XML-Dokumentobjektmodell verwenden. Beim Serialisieren einer Instanz dieses Typs können Sie dieses Feld auf die gewünschten XML-Daten festlegen. Es wird dann serialisiert.

Dies wird mithilfe der IXmlSerializable-Implementierung erreicht. Im generierten IXmlSerializable-Typ ruft die ReadXml-Implementierung die ReadNodes-Methode der XmlSerializableServices-Klasse auf. Bei der Methode handelt es sich um eine Hilfsmethode, die XML-Daten konvertiert, die über einen XmlReader für ein Array mit XmlNode-Objekten bereitgestellt werden. Die WriteXml-Implementierung bewirkt das Gegenteil und konvertiert das Array mit den XmlNode-Objekten in eine Folge von XmlWriter-Aufrufen. Dies wird durch die Verwendung der WriteNodes-Methode erreicht.

Es ist möglich, den Schemaexportprozess über die generierten IXmlSerializable-Klassen auszuführen. Wie bereits erwähnt, erhalten Sie nicht das ursprüngliche Schema zurück. Stattdessen erhalten Sie den standardmäßigen XSD-Typ "anyType" zurück, der ein Platzhalter für einen beliebigen XSD-Typ ist.

Dies wird erreicht, indem das XmlSchemaProviderAttribute-Attribut auf die generierten IXmlSerializable-Klassen angewendet und eine Methode angegeben wird, die die AddDefaultSchema-Methode aufruft, um den Typ "anyType" zu generieren.

Tipp

Der XmlSerializableServices-Typ ist nur vorhanden, um dieses Feature zu unterstützen. Es ist nicht ratsam, den Typ zu einem anderen Zweck zu verwenden.

Importoptionen: Erweiterte Optionen

Bei den folgenden Optionen handelt es sich um erweiterte Importoptionen:

  • CodeProvider-Eigenschaft. Geben Sie den CodeDomProvider an, der verwendet werden soll, um den Code für die generierten Klassen zu generieren. Der Importmechanismus versucht, Features zu vermeiden, die der CodeDomProvider nicht unterstützt. Zum Beispiel unterstützt die Programmiersprache J# keine Generika. Wenn Sie den J#-Codeanbieter in dieser Eigenschaft angeben, werden in der CodeCompileUnit des Importmechanismus keine generischen Typen generiert. Wenn der CodeProvider nicht festgelegt wird, wird der gesamte Satz an .NET Framework-Features ohne Einschränkungen verwendet.
  • DataContractSurrogate-Eigenschaft. Mit dieser Eigenschaft können Sie eine IDataContractSurrogate-Implementierung angeben. IDataContractSurrogate passt den Importprozess an. Weitere Informationen finden Sie unter Datenvertrag-Ersatzzeichen. Standardmäßig wird kein Ersatzzeichen verwendet.

Siehe auch

Referenz

DataContractSerializer
XsdDataContractImporter
XsdDataContractExporter
ImportOptions

Konzepte

Datenvertrags-Schemareferenz
Datenvertrag-Ersatzzeichen
Import und Export von Schemas
Exportieren von Schemas aus Klassen
Datenvertrags-Schemareferenz