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 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 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 nichtnull
zurück, und die IsAny-Eigenschaft des Attributs wird auf ihrem Standardwertfalse
belassen. Dies ist die häufigste Verwendung vonIXmlSerializable
-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 auftrue
fest, oder geben Sie über die Schemaanbietermethode 0 zurück. Die Verwendung einer Schemaanbietermethode ist für Elementtypen optional. Sie können unterXmlSchemaProviderAttribute
anstatt des Methodennamens auch NULL angeben. WennIsAny
jedochtrue
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 demXmlSchemaProviderAttribute
-Attribut gekennzeichnet sind. Stattdessen verwenden sie zur Schemagenerierung die GetSchema-Methode. Dieses Muster wird für denDataSet
-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 dasXmlSchemaProviderAttribute
auf IhreIXmlSerializable
-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 vonWriteXml
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, dasWriteXml
schreibt. Dies ist nur der Fall, wenn beim Erstellen des Serialisierungsprogramms in den KonstruktorenDataContractSerializer
oderNetDataContractSerializer
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 undNetDataContractSerializer
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 aufverifyObjectName
festgelegtemtrue
-Parameter verhält sich genau so wieIsStartObject
, bevor das Objekt gelesen wird.ReadObject
übergibt das Steuerelement dann an dieReadXml
-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 denXmlSerializer
.Wenn das
XmlRootAttribute
-Attribut für Inhalts- oder Legacy-Datasettypen nicht vorhanden ist, exportiert derXmlSerializer
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 vonXmlSerializer
.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 vonDataSet
-Typen in Ihren Verträgen explizit definierte Datenvertragstypen zu verwenden.Beim Importieren von
DataSet
- oderDataTable
-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.