Verwenden der XmlSerializer-Klasse
Windows Communication Foundation(WCF) kann zwei verschiedene Serialisierungstechnologien verwenden, um die Daten in Ihrer Anwendung für die Übertragung zwischen Clients und Diensten in XML umzuwandeln: DataContractSerializer
und XmlSerializer
.
DataContractSerializer
Standardmäßig verwendet WCF die DataContractSerializer-Klasse, um Datentypen zu serialisieren. Dieses Serialisierungsprogramm unterstützt die folgenden Typen:
Primitive Typen (z. B. ganze Zahlen, Zeichenfolgen und Bytearrays) sowie einige spezielle Typen wie XmlElement und DateTime, die als Primitive behandelt werden.
Datenvertragstypen (mit dem DataContractAttribute-Attribut markierte Typen).
Mit dem SerializableAttribute-Attribut markierte Typen, einschließlich Typen, die die ISerializable-Schnittstelle implementieren.
Typen, die die IXmlSerializable-Schnittstelle implementieren.
Viele allgemeine Auflistungstypen, einschließlich vieler generischer Auflistungstypen.
Viele .NET Framework-Typen fallen in die letzten beiden Kategorien und sind daher serialisierbar. Arrays serialisierbarer Typen sind ebenfalls serialisierbar. Eine komplette Liste finden Sie unter Angeben von Datenübertragung in Dienstverträgen.
Der DataContractSerializer, der zusammen mit Datenvertragstypen verwendet wird, ist die empfohlene Methode, um neue WCF-Dienste zu schreiben. Weitere Informationen finden Sie unter Verwenden von Datenverträgen.
XmlSerializer
WCF unterstützt auch die XmlSerializer-Klasse. Die XmlSerializer-Klasse ist nicht exklusiv in WCF verfügbar. Vielmehr handelt es sich hierbei um die gleiche Serialisierungs-Engine, die auch von den ASP.NET-Webdiensten verwendet wird. Die XmlSerializer-Klasse unterstützt deutlich weniger Typen als die DataContractSerializer-Klasse, ermöglicht jedoch eine größere Kontrolle über das resultierende XML und unterstützt den XSD-Schemastandard (XML Schema definition language) stärker. Sie erfordert außerdem keine deklarativen Attribute für die serialisierbaren Typen. Weitere Informationen finden Sie im Thema zur XML-Serialisierung in der .NET Framework-Dokumentation. Die XmlSerializer-Klasse unterstützt keine Datenvertragstypen.
Beim Verwenden von „Svcutil.exe“ oder des Features Dienstverweis hinzufügen in Visual Studio zum Generieren von Clientcode für einen Dienst eines Drittanbieters oder zum Zugreifen auf ein Schema eines Drittanbieters wird automatisch ein geeignetes Serialisierungsmodul für Sie ausgewählt. Wenn das Schema nicht mit DataContractSerializer kompatibel ist, wird XmlSerializer ausgewählt.
Wechseln zum XmlSerializer
Es kann vorkommen, dass Sie manuell zu XmlSerializer wechseln müssen. Dies ist beispielsweise in den folgenden Situationen der Fall:
Beim Migrieren einer Anwendung von ASP.NET-Webdiensten zu WCF sollten Sie vorhandene XmlSerializer-kompatible Typen erneut verwenden, anstatt neue Datenvertragstypen zu erstellen.
Wenn die präzise Steuerung von in Nachrichten enthaltenen XML-Daten wichtig ist, jedoch kein WSDL (Web Services Description Language)-Dokument zur Verfügung steht, z. B. beim Erstellen eines Diensts mit Typen, die einem bestimmten standardisierten, veröffentlichten Schema entsprechen müssen, das nicht mit dem DataContractSerializer kompatibel ist.
Beim Erstellen von Diensten, die dem älteren SOAP-Codierungsstandard folgen.
In diesen und anderen Fällen können Sie manuell zur XmlSerializer-Klasse wechseln, indem Sie das XmlSerializerFormatAttribute
-Attribut auf den Dienst anwenden, wie im folgenden Code dargestellt.
[ServiceContract]
[XmlSerializerFormat]
public class BankingService
{
[OperationContract]
public void ProcessTransaction(BankingTransaction bt)
{
// Code not shown.
}
}
//BankingTransaction is not a data contract class,
//but is an XmlSerializer-compatible class instead.
public class BankingTransaction
{
[XmlAttribute]
public string Operation;
[XmlElement]
public Account fromAccount;
[XmlElement]
public Account toAccount;
[XmlElement]
public int amount;
}
//Notice that the Account class must also be XmlSerializer-compatible.
<ServiceContract(), XmlSerializerFormat()> _
Public Class BankingService
<OperationContract()> _
Public Sub ProcessTransaction(ByVal bt As BankingTransaction)
' Code not shown.
End Sub
End Class
' BankingTransaction is not a data contract class,
' but is an XmlSerializer-compatible class instead.
Public Class BankingTransaction
<XmlAttribute()> _
Public Operation As String
<XmlElement()> _
Public fromAccount As Account
<XmlElement()> _
Public toAccount As Account
<XmlElement()> _
Public amount As Integer
End Class
'Notice that the Account class must also be XmlSerializer-compatible.
Sicherheitsüberlegungen
Hinweis
Beim Wechseln von Serialisierungs-Engines ist große Sorgfalt geboten. Derselbe Typ kann je nach verwendetem Serialisierungsprogramm mehrere Serialisierungskonzepte umfassen. Wenn Sie versehentlich das falsche Serialisierungsprogramm verwenden, legen Sie möglicherweise Informationen aus dem Typ offen, deren Offenlegung Sie nicht beabsichtigt haben.
Beispielsweise serialisiert die DataContractSerializer-Klasse beim Serialisieren von Datenvertragstypen nur mit dem DataMemberAttribute-Attribut markierte Member. Die XmlSerializer-Klasse serialisiert jeden öffentlichen Member. Beachten Sie den Typ im folgenden Code:
[DataContract]
public class Customer
{
[DataMember]
public string firstName;
[DataMember]
public string lastName;
public string creditCardNumber;
}
<DataContract()> _
Public Class Customer
<DataMember()> _
Public firstName As String
<DataMember()> _
Public lastName As String
Public creditCardNumber As String
End Class
Wenn der Typ versehentlich in einem Dienstvertrag verwendet wird, in dem die XmlSerializer-Klasse ausgewählt ist, wird der creditCardNumber
-Member serialisiert, was wahrscheinlich nicht beabsichtigt ist.
Auch wenn die DataContractSerializer-Klasse der Standard ist, können Sie sie explizit für Ihren Dienst auswählen (obwohl dies nie erforderlich sein sollte), indem Sie das DataContractFormatAttribute-Attribut auf den Dienstvertragstyp anwenden.
Das für den Dienst verwendete Serialisierungsprogramm ist ein wesentlicher Bestandteil des Vertrags und kann durch Auswahl einer anderen Bindung oder durch Ändern anderer Konfigurationseinstellungen nicht geändert werden.
Andere wichtige Sicherheitsüberlegungen gelten für die XmlSerializer-Klasse. Es wird zuerst dringend empfohlen, dass jede WCF-Anwendung, die die XmlSerializer-Klasse verwendet, mit einem vor Offenlegung geschützten Schlüssel signiert ist. Diese Empfehlung gilt sowohl für das manuelle Wechseln zu XmlSerializer als auch ein automatisches Wechseln (mit Svcutil.exe, "Dienstverweis hinzufügen" oder ein ähnliches Tool). Der Grund ist, dass die XmlSerializer-Serialisierungs-Engine das Laden von vorgenerierten Serialisierungsassemblys unterstützt, wenn sie mit dem gleichen Schlüssel wie die Anwendung signiert sind. Eine nicht signierte Anwendung ist vollständig ungeschützt gegen die Möglichkeit, dass eine bösartige Assembly, die mit dem erwarteten Namen der vorgenerierten Serialisierungsassembly übereinstimmt, im Anwendungsordner oder im globalen Assemblycache platziert wird. Natürlich muss ein Angreifer zuerst Schreibzugriff auf einen der beiden Speicherorte erhalten, um diese Aktion auszuführen.
Eine weitere Bedrohung, die beim Verwenden von XmlSerializer vorhanden ist, hängt mit dem Schreibzugriff auf den temporären Ordners des Systems zusammen. Die XmlSerializer-Serialisierungs-Engine erstellt und verwendet temporäre Serialisierungsassemblys in diesem Ordner. Sie sollten sich der Tatsache bewusst sein, dass jeder Vorgang mit Schreibzugriff auf den temporären Ordner diese Serialisierungsassemblys mit bösartigem Code überschreiben kann.
Regeln für XmlSerializer-Unterstützung
Sie können mit XmlSerializer kompatible Attribute nicht direkt auf Vertragsvorgangsparameter oder Rückgabewerte anwenden. Sie können jedoch auf typisierte Nachrichten (Nachrichtenvertragstextteile) angewendet werden, wie der folgende Code zeigt:
[ServiceContract]
[XmlSerializerFormat]
public class BankingService
{
[OperationContract]
public void ProcessTransaction(BankingTransaction bt)
{
//Code not shown.
}
}
[MessageContract]
public class BankingTransaction
{
[MessageHeader]
public string Operation;
[XmlElement, MessageBodyMember]
public Account fromAccount;
[XmlElement, MessageBodyMember]
public Account toAccount;
[XmlAttribute, MessageBodyMember]
public int amount;
}
<ServiceContract(), XmlSerializerFormat()> _
Public Class BankingService
<OperationContract()> _
Public Sub ProcessTransaction(ByVal bt As BankingTransaction)
'Code not shown.
End Sub
End Class
<MessageContract()> _
Public Class BankingTransaction
<MessageHeader()> _
Public Operation As String
<XmlElement(), MessageBodyMember()> _
Public fromAccount As Account
<XmlElement(), MessageBodyMember()> _
Public toAccount As Account
<XmlAttribute(), MessageBodyMember()> _
Public amount As Integer
End Class
Beim Anwenden auf typisierte Nachrichtenmember überschreiben diese Attribute Eigenschaften, die mit den typisierten Nachrichtenattributen in Konflikt stehen. Beispielsweise wird im folgenden Code ElementName
durch Name
überschrieben.
[MessageContract]
public class BankingTransaction
{
[MessageHeader] public string Operation;
//This element will be <fromAcct> and not <from>:
[XmlElement(ElementName="fromAcct"), MessageBodyMember(Name="from")]
public Account fromAccount;
[XmlElement, MessageBodyMember]
public Account toAccount;
[XmlAttribute, MessageBodyMember]
public int amount;
}
<MessageContract()> _
Public Class BankingTransaction
<MessageHeader()> _
Public Operation As String
'This element will be <fromAcct> and not <from>:
<XmlElement(ElementName:="fromAcct"), _
MessageBodyMember(Name:="from")> _
Public fromAccount As Account
<XmlElement(), MessageBodyMember()> _
Public toAccount As Account
<XmlAttribute(), MessageBodyMember()> _
Public amount As Integer
End Class
Das MessageHeaderArrayAttribute-Attribut wird nicht unterstützt, wenn XmlSerializer verwendet wird.
Hinweis
In diesem Fall löst XmlSerializer die folgende Ausnahme aus, die vor WCF freigegeben wird: „Für ein auf oberster Schemaebene deklariertes Element darf nicht maxOccurs
> 1 gelten.“ Geben Sie ein Wrapperelement für "more" an, indem Sie XmlArray
oder XmlArrayItem
anstelle von XmlElementAttribute
verwenden oder indem Sie den Wrapped-Parameterstil verwenden.
Wenn Sie eine solche Ausnahme empfangen, prüfen Sie, ob diese Situation zutrifft.
WCF unterstützt das SoapIncludeAttribute- und das XmlIncludeAttribute-Attribut in Nachrichtenverträgen und Vorgangsverträgen nicht; verwenden Sie stattdessen das KnownTypeAttribute-Attribut.
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.
Warnung
Wenn Sie polymorphe Typen verwenden, müssen Sie XmlSchemaProviderAttribute auf den Typ anwenden, um sicherzustellen, dass der richtige Typ serialisiert wird.
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 Schemaanbietermethodenull
zurück. Die Verwendung einer Schemaanbietermethode ist für Elementtypen optional. Sie können unternull
anstatt des Methodennamens auchXmlSchemaProviderAttribute
angeben. WennIsAny
jedochtrue
ist und eine Schemaanbietermethode angegeben ist, muss die Methodenull
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 zuvor 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 zuvor 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 und eines 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 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 "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 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 werden. 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, nichtnull
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 Datenvertragsmodelltrue
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.
XmlSerializer-Legacyverhalten
In .NET Framework 4.0 und früher wurden von XmlSerializer temporäre Serialisierungsassemblys generiert, indem C#-Code in eine Datei geschrieben wurde. Die Datei wurde anschließend in eine Assembly kompiliert. Dieses Verhalten hatte einige unerwünschte Folgen, z. B. das Verzögern der Startzeit für die Serialisierung. In .NET Framework 4.5 wurde das Verhalten geändert, um die Assemblys zu generieren, ohne den Compiler verwenden zu müssen. Einige Entwickler möchten den generierten C#-Code jedoch anzeigen. Sie können mit der folgenden Konfiguration festlegen, dass dieses Legacyverhalten verwendet wird:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.xml.serialization>
<xmlSerializer tempFilesLocation='e:\temp\XmlSerializerBug' useLegacySerializerGeneration="true" />
</system.xml.serialization>
<system.diagnostics>
<switches>
<add name="XmlSerialization.Compilation" value="1" />
</switches>
</system.diagnostics>
</configuration>
Wenn Kompatibilitätsprobleme auftreten, z. B. XmlSerializer
-Fehler beim Serialisieren einer abgeleiteten Klasse mit einer nicht öffentlichen neuen Überschreibung, können Sie mithilfe der folgenden Konfiguration zurück zum Legacyverhalten von XMLSerializer
wechseln:
<configuration>
<appSettings>
<add key="System:Xml:Serialization:UseLegacySerializerGeneration" value="true" />
</appSettings>
</configuration>
Alternativ zur obigen Konfiguration können Sie die folgende Konfiguration auf einem Computer verwenden, auf dem .NET Framework Version 4.5 oder höher ausgeführt wird:
<configuration>
<system.xml.serialization>
<xmlSerializer useLegacySerializerGeneration="true"/>
</system.xml.serialization>
</configuration>
Hinweis
Die <xmlSerializer useLegacySerializerGeneration="true"/>
-Option funktioniert nur auf einem Computer, auf dem .NET Framework Version 4.5 oder höher ausgeführt wird. Der oben genannte appSettings
-Ansatz funktioniert für alle .NET Framework-Versionen.