XML- und ADO.NET-Typen in Datenverträgen

Das WCF-Datenvertragsmodell (Windows Communication Foundation) unterstützt bestimmte Typen, die XML direkt darstellen. Wenn diese Typen in XML serialisiert werden, schreibt das Serialisierungsprogramm den XML-Inhalt dieser Typen ohne weitere Verarbeitung. Unterstützte Typen sind XmlElement, XmlNode-Arrays (jedoch nicht der XmlNode-Typ selbst) sowie Typen, die IXmlSerializable implementieren. Der DataSet- und DataTable-Typ sowie typisierte Datasets werden häufig bei der Datenbankprogrammierung verwendet. Diese Typen implementieren die IXmlSerializable-Schnittstelle und sind deshalb im Datenvertragsmodell serialisierbar. Einige besondere Überlegungen zu diesen Typen sind am Ende dieses Themas aufgeführt.

XML-Typen

XML-Element

Der XmlElement-Typ wird mit seinem XML-Inhalt serialisiert. Verwenden Sie z. B. den folgenden Typ:

[DataContract(Namespace=@"http://schemas.contoso.com")]
public class MyDataContract
{
    [DataMember]
    public XmlElement myDataMember;
    public void TestClass()
    {
        XmlDocument xd = new XmlDocument();
        myDataMember = xd.CreateElement("myElement");
        myDataMember.InnerText = "myContents";
        myDataMember.SetAttribute
         ("myAttribute","myValue");
    }
}
<DataContract([Namespace]:="http://schemas.contoso.com")> _
Public Class MyDataContract
    <DataMember()> _
    Public myDataMember As XmlElement

    Public Sub TestClass()
        Dim xd As New XmlDocument()
        myDataMember = xd.CreateElement("myElement")
        myDataMember.InnerText = "myContents"
        myDataMember.SetAttribute("myAttribute", "myValue")

    End Sub
End Class

Die Serialisierung in XML wird wie folgt durchgeführt:

<MyDataContract xmlns="http://schemas.contoso.com">  
    <myDataMember>  
        <myElement xmlns="" myAttribute="myValue">  
            myContents  
        </myElement>  
    </myDataMember>  
</MyDataContract>  

Beachten Sie, dass immer noch das Wrapper-Datenmemberelement <myDataMember> vorhanden ist. Es gibt keine Möglichkeit, dieses Element im Datenvertragsmodell zu entfernen. Die Serialisierungsprogramme, die dieses Modell verarbeiten (DataContractSerializer und NetDataContractSerializer), können spezielle Attribute in dieses Wrapperelement einfügen. Diese Attribute enthalten das standardmäßige XML-Schemainstanzattribut "nil" (damit das XmlElementnull sein kann) und das Attribut "type" (damit das XmlElement polymorph verwendet werden kann). Außerdem sind die folgenden XML-Attribute spezifisch für WCF: „ID“, „Ref“, „Type“ und „Assembly“. Diese Attribute können ausgegeben werden, um die Verwendung von XmlElement bei aktiviertem Objektdiagramm-Beibehaltungsmodus zu unterstützen, oder indem NetDataContractSerializer verwendet wird. (Weitere Informationen zum Modus der Objektgrapherhaltung finden Sie unter Serialisierung und Deserialisierung.)

Arrays oder Auflistungen von XmlElement sind zulässig und werden wie andere Arrays oder Auflistungen behandelt. Es wird ein Wrapperelement für die gesamte Auflistung und ein separates Wrapperelement (auf ähnliche Weise wie im vorherigen Beispiel) für jedes im Array verwendet.

Bei der Deserialisierung erstellt das Deserialisierungsprogramm aus den eingehenden XML-Daten ein XmlElement. Ein gültiges übergeordnetes XmlDocument wird vom Deserialisierungsprogramm bereitgestellt.

Stellen Sie sicher, dass für das XML-Fragment, das in ein XmlElement deserialisiert wird, alle verwendeten Präfixe definiert sind, und dass es nicht von den Präfixdefinitionen übergeordneter Elemente abhängig ist. Dies ist nur von Bedeutung, wenn Sie DataContractSerializer verwenden, um auf XML von einer anderen Quelle (als DataContractSerializer) zuzugreifen.

Bei Verwendung mit DataContractSerializer kann das XmlElement polymorph zugewiesen werden, jedoch nur für einen Datenmember vom Typ Object. Auch wenn es IEnumerable implementiert, kann ein XmlElement nicht als Auflistungstyp verwendet und keinem IEnumerable-Datenmember zugeordnet werden. Wie bei allen polymorphen Zuordnungen gibt der DataContractSerializer den Datenvertragsnamen im resultierenden XML-Code aus. In diesem Fall lautet er „XmlElement“ im Namespace http://schemas.datacontract.org/2004/07/System.Xml.

Mit NetDataContractSerializer wird jede gültige polymorphe Zuweisung von XmlElement (zu Object oder IEnumerable) unterstützt.

Versuchen Sie nicht, eines der Serialisierungsprogramme in Verbindung mit Typen zu verwenden, die von XmlElement abgeleitet sind, ob polymorph oder auf andere Weise.

XmlNode-Array

Das Verwenden von XmlNode-Arrays ähnelt stark der Verwendung von XmlElement. Wenn Sie XmlNode-Arrays verwenden, können Sie flexibler arbeiten, als wenn Sie XmlElement verwenden. Sie können innerhalb des Datenmember-Wrapperelements mehrere Elemente schreiben. Neben Elementen können Sie auch andere Inhalte in das Datenmember-Wrapperelement einfügen, zum Beispiel XML-Kommentare. Außerdem können Sie bei Bedarf Attribute in das Datenmember-Wrapperelement einfügen. Sie können diese Schritte ausführen, indem Sie das XmlNode-Array mit spezifischen von XmlNode abgeleiteten Klassen auffüllen, zum Beispiel mit XmlAttribute, XmlElement oder XmlComment. Verwenden Sie z. B. den folgenden Typ:

[DataContract(Namespace="http://schemas.contoso.com")]
public class MyDataContract
{
    [DataMember]
    public XmlNode[] myDataMember = new XmlNode[4];
    public void TestClass()
    {
        XmlDocument xd = new XmlDocument();
        XmlElement xe = xd.CreateElement("myElement");
        xe.InnerText = "myContents";
        xe.SetAttribute
         ("myAttribute","myValue");
    
        XmlAttribute atr = xe.Attributes[0];
        XmlComment cmnt = xd.CreateComment("myComment");
        
      myDataMember[0] = atr;
      myDataMember[1] = cmnt;
      myDataMember[2] = xe;
      myDataMember[3] = xe;
    }
}
<DataContract([Namespace]:="http://schemas.contoso.com")> _
Public Class MyDataContract
    <DataMember()> _
    Public myDataMember(3) As XmlNode

    Public Sub TestClass()
        Dim xd As New XmlDocument()
        Dim xe As XmlElement = xd.CreateElement("myElement")
        xe.InnerText = "myContents"
        xe.SetAttribute("myAttribute", "myValue")

        Dim atr As XmlAttribute = xe.Attributes(0)
        Dim cmnt As XmlComment = xd.CreateComment("myComment")

        myDataMember(0) = atr
        myDataMember(1) = cmnt
        myDataMember(2) = xe
        myDataMember(3) = xe

    End Sub

End Class

Nach der Serialisierung sind die sich ergebenden XML-Daten folgendem Code ähnlich:

<MyDataContract xmlns="http://schemas.contoso.com">  
  <myDataMember myAttribute="myValue">  
     <!--myComment-->  
     <myElement xmlns="" myAttribute="myValue">  
 myContents  
     </myElement>  
     <myElement xmlns="" myAttribute="myValue">  
       myContents  
     </myElement>  
  </myDataMember>  
</MyDataContract>  

Beachten Sie, dass das Datenmember-Wrapperelement <myDataMember> ein Attribut, einen Kommentar und zwei Elemente enthält. Dies sind die vier XmlNode-Instanzen, die serialisiert wurden.

Ein XmlNode-Array, das zu ungültigen XML-Daten führen würde, kann nicht serialisiert werden. Ein Array mit zwei XmlNode-Instanzen, von der die erste ein XmlElement und die zweite ein XmlAttribute ist, ist zum Beispiel ungültig, da diese Folge keiner gültigen XML-Instanz entspricht (es gibt keine Möglichkeit, das Attribut anzufügen).

Bei der Deserialisierung eines XmlNode-Arrays werden Knoten erstellt und mit den Informationen aus den eingehenden XML-Daten aufgefüllt. Ein gültiges übergeordnetes XmlDocument wird vom Deserialisierungsprogramm bereitgestellt. Alle Knoten werden deserialisiert. Dazu zählen auch alle Attribute im Datenmember-Wrapperelement, aber nicht die Attribute, die von den WCF-Serialisierungsmodulen dort platziert wurden (z. B. die Attribute, die zum Angeben der polymorphen Zuweisung verwendet werden). Die Einschränkung in Bezug auf die Definition aller Namespacepräfixe im XML-Fragment gilt für die Deserialisierung von XmlNode-Arrays genauso, wie sie für die Deserialisierung von XmlElement gilt.

Wenn Sie die Serialisierungsprogramme bei aktivierter Objektdiagrammbeibehaltung verwenden, wird die Objektgleichheit nur auf der Ebene der XmlNode-Arrays beibehalten, nicht für die einzelnen XmlNode-Instanzen.

Versuchen Sie nicht, ein XmlNode-Array zu serialisieren, wenn einer oder mehrere Knoten auf null festgelegt sind. Es ist zulässig, dass das gesamte Array null ist, nicht jedoch ein einzelner XmlNode im Array. Wenn der gesamte Arraymember 0 ist, enthält das Datenmember-Wrapperelement ein spezielles Attribut, das diesen Nullwert angibt. Bei der Deserialisierung wird auch der ganze Arraymember 0.

Nur normale XmlNode-Arrays werden vom Serialisierungsprogramm besonders behandelt. Datenmember, die als andere, XmlNode enthaltende Auflistungstypen deklariert sind, oder Datenmember, die als Arrays von Typen deklariert sind, die von XmlNode abgeleitet sind, werden nicht besonders behandelt. Aus diesem Grund sind sie normalerweise nicht serialisierbar, es sei denn, sie erfüllen auch eines der Kriterien für die Serialisierbarkeit.

Arrays oder Auflistungen von Arrays von XmlNode sind zulässig. Es wird ein Wrapperelement für die gesamte Auflistung und ein separates Wrapperelement (auf ähnliche Weise wie im Beispiel oben) für jedes -Array im äußeren Array bzw. in der äußeren Auflistung verwendet.

Das Auffüllen eines Datenmembers vom Typ Array von Object oder Array von IEnumerable mit XmlNode-Instanzen führt nicht dazu, dass der Datenmember als Array mit XmlNode-Instanzen behandelt wird. Jeder Arraymember wird getrennt serialisiert.

Bei der Verwendung mit DataContractSerializer können XmlNode-Arrays polymorph zugewiesen werden, jedoch nur für einen Datenmember vom Typ Object. Auch wenn es IEnumerable implementiert, kann ein XmlNode-Array nicht als Auflistungstyp verwendet und keinem IEnumerable-Datenmember zugeordnet werden. Wie bei allen polymorphen Zuordnungen gibt der DataContractSerializer den Datenvertragsnamen im resultierenden XML-Code aus – in diesem Fall „ArrayOfXmlNode“ im Namespace http://schemas.datacontract.org/2004/07/System.Xml. Bei Verwendung mit NetDataContractSerializer wird jede gültige Zuweisung eines XmlNode-Arrays unterstützt.

Schemaüberlegungen

Ausführliche Informationen zur Schemazuordnung von XML-Typen finden Sie unter Datenvertrags-Schemareferenz. Dieser Abschnitt enthält eine Zusammenfassung der wichtigen Punkte.

Ein Datenmember vom Typ XmlElement wird einem Element zugeordnet, das mithilfe des folgenden anonymen Typs definiert wurde.

<xsd:complexType>  
   <xsd:sequence>  
      <xsd:any minOccurs="0" processContents="lax" />  
   </xsd:sequence>  
</xsd:complexType>  

Ein Datenmember vom Typ XmlNode-Array wird einem Element zugeordnet, das mithilfe des folgenden anonymen Typs definiert wurde.

<xsd:complexType mixed="true">  
   <xsd:sequence>  
      <xsd:any minOccurs="0" maxOccurs="unbounded" processContents="lax" />  
   </xsd:sequence>  
   <xsd:anyAttribute/>  
</xsd:complexType>  

Typen, die die IXmlSerializable-Schnittstelle implementieren

Typen, die die IXmlSerializable-Schnittstelle implementieren, werden von DataContractSerializer vollständig unterstützt. Sie sollten das XmlSchemaProviderAttribute-Attribut immer auf diese Typen anwenden, um das dazugehörige Schema zu steuern.

Es gibt drei Varianten von Typen, die IXmlSerializable implementieren: Typen, die beliebigen Inhalt darstellen, Typen, die ein einzelnes Element darstellen, und ältere DataSet-Typen.

  • Inhaltstypen verwenden eine vom XmlSchemaProviderAttribute-Attribut angegebene Schemaanbietermethode. Die Methode gibt nicht null zurück, und die IsAny-Eigenschaft des Attributs wird auf ihrem Standardwert false belassen. Dies ist die häufigste Verwendung von IXmlSerializable-Typen.

  • Elementtypen werden verwendet, wenn ein IXmlSerializable-Typ seinen eigenen Stammelementnamen kontrollieren muss. Um einen Typ als Elementtyp zu kennzeichnen, legen Sie entweder die IsAny-Eigenschaft des XmlSchemaProviderAttribute-Attributs auf true fest, oder geben Sie über die Schemaanbietermethode 0 zurück. Die Verwendung einer Schemaanbietermethode ist für Elementtypen optional. Sie können unter XmlSchemaProviderAttribute anstatt des Methodennamens auch NULL angeben. Wenn IsAny jedoch true ist und eine Schemaanbietermethode angegeben ist, muss die Methode NULL zurückgeben.

  • Bei älteren DataSet-Typen handelt es sich um IXmlSerializable-Typen, die nicht mit dem XmlSchemaProviderAttribute-Attribut gekennzeichnet sind. Stattdessen verwenden sie zur Schemagenerierung die GetSchema-Methode. Dieses Muster wird für den DataSet-Typ und seine von ihm abgeleiteten typisierten Dataset-Klassen in älteren Versionen von .NET Framework verwendet. Es ist jedoch veraltet und wird nur aus Legacygründen noch unterstützt. Verlassen Sie sich nicht auf dieses Muster, und wenden Sie immer das XmlSchemaProviderAttribute auf Ihre IXmlSerializable-Typen an.

IXmlSerializable-Inhaltstypen

Wenn Sie einen Datenmember eines Typs serialisieren, der IXmlSerializable implementiert und ein wie vorher definierter Inhaltstyp ist, schreibt das Serialisierungsprogramm das Wrapperelement für den Datenmember und übergibt die Steuerung an die WriteXml-Methode. Die WriteXml-Implementierung kann beliebige XML-Daten schreiben, auch zum Hinzufügen der Attribute zum Wrapperelement. Nachdem WriteXml abgeschlossen ist, schließt das Serialisierungsprogramm das Element.

Wenn Sie einen Datenmember eines Typs deserialisieren, der IXmlSerializable implementiert und ein wie vorher definierter Inhaltstyp ist, ordnet das Deserialisierungsprogramm den XML-Reader im Wrapperelement für den Datenmember an und übergibt die Steuerung an die ReadXml-Methode. Die Methode muss das ganze Element lesen, einschließlich des Start- und Endtags. Stellen Sie sicher, dass der ReadXml-Code auch den Fall verarbeitet, in dem das Element leer ist. Außerdem sollte sich Ihre ReadXml-Implementierung nicht darauf verlassen, dass das Wrapperelement einen bestimmten Namen aufweist. Der Name wird vom Serialisierungsprogramm ausgewählt und kann variieren.

Es ist zulässig, IXmlSerializable-Inhaltstypen polymorph zuzuweisen, zum Beispiel zu Datenmembern vom Typ Object. Es ist auch zulässig, dass die Typinstanzen NULL sind. Außerdem ist es möglich, IXmlSerializable-Typen bei aktivierter Objektdiagrammbeibehaltung und mit NetDataContractSerializer zu verwenden. Für all diese Features muss das WCF-Serialisierungsmodul bestimmte Attribute an das Wrapperelement anfügen („nil“ und „type“ im XML-Schemainstanznamespace und „Id“, „Ref“, „Type“ und „Assembly“ in einem WCF-spezifischen Namespace).

Bei der Implementierung von ReadXml zu ignorierende Attribute

Bevor die Steuerung an Ihren ReadXml-Code übergeben wird, untersucht das Deserialisierungsprogramm das XML-Element, erkennt diese speziellen XML-Attribute und führt die erforderlichen Aktionen aus. Wenn "nil" zum Beispiel true ist, wird ein Nullwert deserialisiert, und ReadXml wird nicht aufgerufen. Falls Polymorphie erkannt wird, wird der Inhalt des Elements deserialisiert, als ob es sich um einen anderen Typ handeln würde. Die ReadXml-Implementierung des polymorph zugewiesenen Typs wird aufgerufen. Eine ReadXml-Implementierung sollte diese speziellen Attribute auf jeden Fall ignorieren, da sie vom Deserialisierungsprogramm verarbeitet werden.

Schemaüberlegungen für IXmlSerializable-Inhaltstypen

Beim Exportieren eines Schemas aus einem IXmlSerializable-Inhaltstyp wird die Schemaanbietermethode aufgerufen. Ein XmlSchemaSet wird an die Schemaanbietermethode übergeben. Die Methode kann dem Schemasatz gültige Schemas hinzufügen. Der Schemasatz enthält das Schema, das zum Zeitpunkt des Schemaexports bereits bekannt ist. Wenn die Schemaanbietermethode dem Schemasatz ein Element hinzufügen muss, muss sie ermitteln, ob ein XmlSchema mit dem geeigneten Namespace im Satz bereits vorhanden ist. Falls dies der Fall ist, muss die Schemaanbietermethode das neue Element dem vorhandenen XmlSchema hinzufügen. Andernfalls muss sie eine neue XmlSchema-Instanz erstellen. Dies ist wichtig, wenn Arrays mit IXmlSerializable-Typen verwendet werden. Wenn Sie zum Beispiel über einen IXmlSerializable-Typ verfügen, der als Typ "A" in Namespace "B" exportiert wird, ist es möglich, dass der Schemasatz beim Aufrufen der Schemaanbietermethode das Schema "B" bereits enthält, um den Typ "ArrayOfA" aufzunehmen.

Zusätzlich zum Hinzufügen von Typen zum XmlSchemaSet muss die Schemaanbietermethode für Inhaltstypen einen anderen Wert als NULL zurückgeben. Sie kann ein XmlQualifiedName-Element zurückgeben, das den Namen des Schematyps angibt, der für den jeweiligen IXmlSerializable-Typ verwendet wird. Dieser qualifizierte Name dient auch als Datenvertragsname und Namespace für den Typ. Es ist zulässig, einen Typ zurückzugeben, der nicht im Schemasatz vorhanden ist, wenn dies direkt nach der Rückgabe der Schemaanbietermethode erfolgt. Es wird jedoch vorausgesetzt, dass der Typ nach dem Export aller verwandten Typen (die Export-Methode wird für alle relevanten Typen von XsdDataContractExporter aufgerufen, und es wird auf die Schemas-Eigenschaft zugegriffen) im Schemasatz vorhanden ist. Das Zugreifen auf die Schemas-Eigenschaft, bevor alle relevanten Export-Aufrufe durchgeführt wurden, kann zu einer XmlSchemaException führen. Weitere Informationen zum Exportprozess finden Sie unter Exportieren von Schemas aus Klassen.

Die Schemaanbietermethode kann auch den zu verwendenden XmlSchemaType zurückgeben. Der Typ kann anonym oder nicht anonym sein. Wenn er anonym ist, wird das Schema für den IXmlSerializable-Typ jeweils als anonymer Typ exportiert, wenn der IXmlSerializable-Typ als Datenmember verwendet wird. Der IXmlSerializable-Typ verfügt trotzdem noch über einen Datenvertragsnamen und einen Namespace. (Dies wird wie unter Datenvertragsnamen beschrieben bestimmt, mit der Ausnahme, dass das DataContractAttribute-Attribut nicht zum Anpassen des Namens verwendet werden kann.) Wenn der Typ nicht anonym ist, muss es sich um einen der Typen im XmlSchemaSet handeln. Dies entspricht dem Zurückgeben von XmlQualifiedName für den Typ.

Zusätzlich wird für den Typ eine globale Elementdeklaration exportiert. Wenn auf den Typ nicht das XmlRootAttribute-Attribut angewendet wurde, weist das Element denselben Namen und Namespace wie der Datenvertrag auf, und seine nillable-Eigenschaft ist true. Die einzige Ausnahme dabei ist der Schemanamespace (http://www.w3.org/2001/XMLSchema). Wenn der Datenvertrag des Typs in diesem Namespace enthalten ist, befindet sich das entsprechende globale Element im leeren Namespace, da es nicht zulässig ist, dem Schemanamespace neue Elemente hinzuzufügen. Wenn das XmlRootAttribute-Attribut auf den Typ angewendet wurde, wird die globale Elementdeklaration unter Verwendung der Eigenschaften ElementName, Namespace und IsNullable exportiert. Die bei angewendetem XmlRootAttribute geltenden Standardeinstellungen sind der Datenvertragsname, ein leerer Namespace und der Wert „true“ für die „nillable“ (kann NULL sein).

Die gleichen Regeln für die globale Elementdeklaration gelten für Legacy-Datasettypen. Beachten Sie, dass das XmlRootAttribute keine globalen Elementdeklarationen überschreiben kann, die mithilfe von benutzerdefiniertem Code hinzugefügt wurden. Diese können mithilfe der Schemaanbietermethode dem XmlSchemaSet oder über GetSchema für Legacy-Datasettypen hinzugefügt worden sein.

IXmlSerializable-Elementtypen

Für IXmlSerializable-Elementtypen ist entweder die IsAny-Eigenschaft auf true festgelegt, oder ihre Schemaanbietermethode gibt null zurück.

Das Serialisieren und Deserialisieren eines Elementtyps ähnelt stark dem Serialisieren und Deserialisieren eines Inhaltstyps. Es gibt jedoch einige wichtige Unterschiede:

  • Von der WriteXml-Implementierung wird erwartet, dass sie genau ein Element schreibt (das natürlich mehrere untergeordnete Elemente enthalten kann). Sie sollte keine Attribute außerhalb dieses einzelnen Elements, mehrerer gleichgeordneter Elemente oder gemischten Inhalts schreiben. Das Element ist ggf. leer.

  • Die ReadXml-Implementierung sollte das Wrapperelement nicht lesen. Es wird erwartet, dass sie das einzelne Element liest, das von WriteXml erzeugt wird.

  • Wenn das Serialisierungsprogramm regelmäßig einen Elementtyp serialisiert (zum Beispiel als Datenmember in einem Datenvertrag), gibt das Serialisierungsprogramm ein Wrapperelement aus, bevor WriteXml aufgerufen wird. Dies entspricht der Vorgehensweise bei Inhaltstypen. Bei der Serialisierung eines Elementtyps auf der obersten Ebene gibt das Serialisierungsprogramm normalerweise jedoch kein Wrapperelement für das Element aus, das WriteXml schreibt. Dies ist nur der Fall, wenn beim Erstellen des Serialisierungsprogramms in den Konstruktoren DataContractSerializer oder NetDataContractSerializer explizit ein Stammname und ein Namespace angegeben wurde. Weitere Informationen finden Sie unter Serialisierung und Deserialisierung.

  • Beim Serialisieren eines Elementtyps auf der obersten Ebene, ohne zur Entwurfszeit den Stammnamen und einen Namespace anzugeben, führen WriteStartObject und WriteEndObject im Wesentlichen keine Aktionen aus, und WriteObjectContent ruft einfach WriteXml auf. In diesem Modus kann das Objekt, das serialisiert wird, nicht NULL sein und nicht polymorph zugewiesen werden. Außerdem kann die Objektdiagrammbeibehaltung nicht aktiviert und NetDataContractSerializer kann nicht verwendet werden.

  • Beim Deserialisieren eines Elementtyps auf der obersten Ebene, ohne zur Entwurfszeit den Stammnamen und den Namespace anzugeben, gibt IsStartObject den Wert true zurück, wenn der Anfang eines beliebigen Elements gefunden werden kann. ReadObject mit auf verifyObjectName festgelegtem true-Parameter verhält sich genau so wie IsStartObject, bevor das Objekt gelesen wird. ReadObject übergibt das Steuerelement dann an die ReadXml-Methode.

Das Schema, das für die Elementtypen exportiert wird, entspricht dem Schema für den XmlElement-Typ, wie in einem Abschnitt weiter oben beschrieben. Es gilt jedoch die Ausnahme, dass die Schemaanbietermethode wie bei Inhaltstypen dem XmlSchemaSet zusätzliche Schemas hinzufügen kann. Das Verwenden des XmlRootAttribute-Attributs mit Elementtypen ist nicht zulässig, und globale Elementdeklarationen werden für diese Typen nicht ausgegeben.

Unterschiede zu XmlSerializer

Die IXmlSerializable-Schnittstelle und das XmlSchemaProviderAttribute- und XmlRootAttribute-Attribut werden vom XmlSerializer auch verstanden. Aber es gibt einige Unterschiede dabei, wie diese Elemente im Datenvertragsmodell behandelt werden. Die wichtigsten Unterschiede werden im Folgenden zusammengefasst:

  • Die Schemaanbietermethode muss öffentlich sein, um im XmlSerializer verwendet werden zu können. Sie muss jedoch nicht öffentlich sein, um im Datenvertragsmodell verwendet werden zu können.

  • Die Schemaanbietermethode wird aufgerufen, wenn für IsAny im Datenvertragsmodell "true" gilt, jedoch nicht für den XmlSerializer.

  • Wenn das XmlRootAttribute-Attribut für Inhalts- oder Legacy-Datasettypen nicht vorhanden ist, exportiert der XmlSerializer eine globale Elementdeklaration in den leeren Namespace. Im Datenvertragsmodell ist der verwendete Namespace normalerweise der Datenvertragsnamespace, wie bereits beschrieben.

Beachten Sie diese Unterschiede, wenn Sie Typen erstellen, die mit beiden Serialisierungstechnologien verwendet werden.

Importieren von IXmlSerializable-Schemas

Beim Importieren eines Schemas, das aus IXmlSerializable-Typen generiert wurde, gibt es verschiedene Möglichkeiten:

  • Bei dem generierten Schema kann es sich um ein gültiges Datenvertragsschema handeln, wie unter Datenvertrags-Schemareferenz beschrieben. In diesem Fall kann das Schema auf die übliche Weise importiert werden, und es werden normale Datenvertragstypen generiert.

  • Bei dem generierten Schema kann es sich auch um ein nicht gültiges Datenvertragsschema handeln. Ihre Schemaanbietermethode kann zum Beispiel Schemas mit XML-Attributen generieren, die im Datenvertragsmodell nicht unterstützt werden. In diesem Fall können Sie das Schema als IXmlSerializable-Typen importieren. Dieser Importmodus ist standardmäßig nicht aktiviert, kann aber auf einfache Weise aktiviert werden, zum Beispiel mit der Befehlszeilenoption /importXmlTypes für das ServiceModel Metadata Utility-Tool (Svcutil.exe). Dies wird im Artikel Importieren von Schemas zum Generieren von Klassen ausführlich beschrieben. Beachten Sie, dass Sie für die Typinstanzen direkt mit den XML-Daten arbeiten müssen. Sie können auch erwägen, eine andere Serialisierungstechnologie zu verwenden, die einen größeren Schemabereich unterstützt. Weitere Informationen finden Sie im Thema zur Verwendung von XmlSerializer.

  • Es ist ratsam, Ihre vorhandenen IXmlSerializable-Typen im Proxy wiederzuverwenden, anstatt neue zu generieren. In diesem Fall können Sie die Funktion mit den referenzierten Typen verwenden, die im Thema zum Importieren von Schemas zum Generieren von Typen beschrieben ist, um den wiederzuverwendenden Typ anzugeben. Dies entspricht dem Verwenden des Schalters /reference für „svcutil.exe“. Damit wird die Assembly angegeben, die die wiederzuverwendenden Typen enthält.

Darstellen von beliebigen XML-Daten in Datenverträgen

Mithilfe der Typen XmlElement, XmlNode-Array und IXmlSerializable können Sie beliebige XML-Daten in das Datenvertragsmodell einfügen. DataContractSerializer und NetDataContractSerializer übergeben diesen XML-Inhalt an den verwendeten XML-Writer, ohne dabei den Prozess zu beeinträchtigen. Die XML-Writer können jedoch bestimmte Einschränkungen für die XML-Daten erzwingen, die sie schreiben. Unten sind einige wichtige Beispiele aufgeführt:

  • Die XML-Writer lassen beim Schreiben eines anderen Dokuments in der Regel keine XML-Dokumentdeklaration zu (z. B. <?xml version=’1.0’ ?>). Sie können kein vollständiges XML-Dokument als Array-XmlNode für einen Datenmember serialisieren. Dazu müssen Sie entweder die Dokumentdeklaration entfernen oder Ihr eigenes Codierungsschema für die Darstellung verwenden.

  • Alle mit WCF gelieferten XML-Writer lehnen XML-Verarbeitungsanweisungen <? … ?>) und Dokumenttypdefinitionen (<! … >) ab, da diese in SOAP-Nachrichten nicht zulässig sind. Auch hier können Sie Ihren eigenen Codierungsmechanismus verwenden, um diese Einschränkung zu umgehen. Wenn Sie dies in die sich ergebenden XML-Daten einfügen müssen, können Sie einen benutzerdefinierten Encoder schreiben, der XML-Writer mit der entsprechenden Unterstützung verwendet.

  • Wenn Sie WriteXml implementieren, sollten Sie es vermeiden, die WriteRaw-Methode für den XML-Writer aufzurufen. WCF verwendet verschiedene XML-Codierungen (einschließlich Binärcodierung), sodass es sehr schwierig bzw. unmöglich ist, WriteRaw so zu verwenden, dass das Ergebnis für jede Codierung verwendbar ist.

  • Vermeiden Sie beim Implementieren von WriteXml die Verwendung der Methoden WriteEntityRef und WriteNmToken, die von den mitgelieferten XML-Writern von WCF nicht unterstützt werden.

Verwenden von DataSet, typisiertem DataSet und DataTable

Die Verwendung dieser Typen wird im Datenvertragsmodell vollständig unterstützt. Beachten Sie beim Verwenden dieser Typen die folgenden Punkte:

  • Das Schema für diese Typen (vor allem DataSet und die zugehörigen abgeleiteten typisierten Klassen) ist mit einigen Nicht-WCF-Plattformen möglicherweise nicht interoperabel oder kann bei Verwendung mit diesen Plattformen deutliche Einschränkungen aufweisen. Außerdem kann die Verwendung des DataSet-Typs zu Leistungseinbußen führen. Zudem kann es das Versehen Ihrer Anwendung mit einer Versionsangabe erschweren. Sie können erwägen, anstelle von DataSet-Typen in Ihren Verträgen explizit definierte Datenvertragstypen zu verwenden.

  • Beim Importieren von DataSet- oder DataTable-Schemas ist es wichtig, auf diese Typen zu verweisen. Sie können dies mithilfe des Befehlszeilentools „Svcutil.exe“ erreichen, indem Sie den System.Data.dll-Assemblynamen an die Option /reference übergeben. Wenn Sie typisierte Datasetschemas importieren, müssen Sie auf den Typ des typisierten Datasets verweisen. Übergeben Sie bei Verwendung von „Svcutil.exe“ den Speicherort der Assembly des typisierten Datasets an die Option /reference. Weitere Informationen zum Verweisen auf Typen finden Sie unter Importieren des Schemas zum Generieren von Klassen.

Die Unterstützung typisierter DataSets im Datenvertragsmodell ist beschränkt. Typisierte DataSets können serialisiert und deserialisiert werden und können ihr Schema exportieren. Jedoch kann der Datenvertragsschemaimport keine neuen typisierte Dataset-Typen aus dem Schema generieren, sondern nur schon vorhandene wiederverwenden. Sie können mithilfe des /r-Schalters von Svcutil.exe auf ein vorhandenes typisiertes DataSet verweisen. Wenn Sie versuchen, Svcutil.exe ohne den /r-Schalter für einen Dienst einzusetzen, der ein typisiertes DataSet verwendet, wird automatisch ein alternatives Serialisierungsprogramm (XmlSerializer) ausgewählt. Wenn Sie den DataContractSerializer verwenden und DataSets aus dem Schema generieren müssen, können Sie zu dem folgenden Verfahren greifen: Generieren Sie die typisierten DataSet-Typen (indem Sie das Tool Xsd.exe mit dem Schalter /d für den Dienst verwenden), kompilieren Sie die Typen, und verweisen Sie dann mithilfe des /r-Schalters von Svcutil.exe auf diese Typen.

Siehe auch