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 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 null zurück. Die Verwendung einer Schemaanbietermethode ist für Elementtypen optional. Sie können unter null anstatt des Methodennamens auch XmlSchemaProviderAttribute 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 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 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 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, 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.

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.

Siehe auch