XML- und ADO.NET-Typen in Datenverträgen
Das Windows Communication Foundation (WCF)-Datenvertragsmodell 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 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
[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");
}
}
Die Serialisierung in XML wird wie folgt durchgeführt:
<MyDataContract xmlns="http://schemas.contoso.com">
<myDataMember>
<myElement 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 XmlElement NULL 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 über zum Objektdiagramm-Beibehaltungsmodus 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 <myDataMember>
XmlElement 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 der 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 Zuweisungen gibt DataContractSerializer den Datenvertragsnamen in den sich ergebenden XML-Daten aus. In diesem Fall ist dies "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 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
[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;
}
}
Nach der Serialisierung sind die sich ergebenden XML-Daten folgendem Code ähnlich:
<MyDataContract xmlns="http://schemas.contoso.com">
<myDataMember myAttribute="myValue">
<!--myComment-->
<myElement myAttribute="myValue">
myContents
</myElement>
<myElement 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. Es werden alle Knoten deserialisiert. Dazu zählen auch alle Attribute im Datenmember-Wrapperelement, jedoch nicht die Attribute, die von den WCF-Serialisierungsprogrammen dort angeordnet wurden (zum Beispiel 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 <myDataMember>
XmlNode 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 Zuweisungen gibt DataContractSerializer den Datenvertragsnamen in den sich ergebenden XML-Daten aus. In diesem Fall ist dies "ArrayOfXmlNode" im Namespace "http://schemas.datacontract.org/2004/07/System.Xml". Wenn die Verwendung mit dem NetDataContractSerializer erfolgt, 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. Diese Funktionen erfordern es, dass das WCF-Serialisierungsprogramm bestimmte Attribute in das Wrapperelement einfügt ("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 über über den 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, jedoch mit der Ausnahme, dass das DataContractAttribute-Attribut nicht zum Anpassen des Namens verwendet werden kann.) Wenn er 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 "nil"-fähige 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 auf den Typ das XmlRootAttribute-Attribut angewendet wurde, wird die globale Elementdeklaration exportiert, indem Folgendes verwendet wird: die Eigenschaften ElementName, Namespace und IsNullable. Die bei angewendetem XmlRootAttribute geltenden Standardeinstellungen sind der Datenvertragsname, ein leerer Namespace und der Wert "true" für die Nullfähigkeit ("nillable").
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, falls der Anfang eines beliebigen Elements gefunden werden kann. ReadObject, für das der verifyObjectName-Parameter auf true festgelegt ist, verhält sich genauso wie IsStartObject, bevor das Objekt gelesen wird. ReadObject übergibt die Steuerung dann einfach 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 dem Befehlszeilenschalter /importXmlTypes von ServiceModel Metadata Utility-Tool (Svcutil.exe). Ausführliche Informationen hierzu finden Sie unter Importieren von Schemas zum Generieren von Klassen. 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 in Verbindung mit der Datei svcutil.exe. Dabei 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 (zum Beispiel <?xml version=’1.0’ ?>). Sie können kein vollständiges XML-Dokument als XmlNode-Array 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 weisen XML-Verarbeitungsanweisungen (<? … ?>) und Dokumenttypdefinitionen (<! … >) zurück, 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.
Vermeiden Sie beim Implementieren von WriteXml den Aufruf der WriteRaw-Methode für den XML-Writer. WCF verwendet verschiedene XML-Codierungen (einschließlich binär), sodass es sehr schwierig bzw. nahezu 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 möglicherweise nicht interoperabel mit einigen Nicht-WCF-Plattformen oder kann bei Verwendung dieser 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 den Schalter /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 den Schalter /reference. Weitere Informationen über zum Verweisen auf Typen finden Sie unter Importieren von 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
Verweis
DataContractSerializer
IXmlSerializable
Konzepte
Verwenden von Datenverträgen
Vom Datenvertragsserialisierer unterstützte Typen