Teilen über


Serialisierung und Deserialisierung

Windows Communication Foundation (WCF) enthält ein neues Serialisierungsmodul, das DataContractSerializer. Der DataContractSerializer übersetzt in beide Richtungen zwischen .NET Framework-Objekten und XML. In diesem Thema wird erläutert, wie der Serialisierer funktioniert.

Beim Serialisieren von .NET Framework-Objekten versteht der Serialisierungsprogrammierer eine Vielzahl von Serialisierungsprogrammierungsmodellen, einschließlich des neuen Datenvertragsmodells . Eine vollständige Liste der unterstützten Typen finden Sie unter Typen, die vom Serializer für den Datenvertrag unterstützt werden. Eine Einführung in Datenverträge finden Sie unter Verwenden von Datenverträgen.

Beim Deserialisieren von XML verwendet der Serialisierer die XmlReader- und XmlWriter-Klassen. Es unterstützt außerdem die Klassen XmlDictionaryReader und XmlDictionaryWriter, um es zu ermöglichen, optimierte XML-Daten in einigen Fällen zu erzeugen, z. B. bei Verwendung des WCF-Binär-XML-Formats.

WCF enthält auch einen Begleit-Serialisierer, den NetDataContractSerializer. Die NetDataContractSerializer:

  • Ist nicht sicher. Weitere Informationen finden Sie im Sicherheitsleitfaden für BinaryFormatter.
  • Ähnelt den Serialisierungsmodulen BinaryFormatter und SoapFormatter, da auch hier .NET Framework-Typnamen zusammen mit den serialisierten Daten ausgegeben werden.
  • Wird verwendet, wenn die Endpunkte für die Serialisierung und die Deserialisierung die gleichen Datentypen verwenden.

Sowohl DataContractSerializer als auch NetDataContractSerializer werden von einer gemeinsamen Basisklasse, XmlObjectSerializer, abgeleitet.

Warnung

DataContractSerializer serialisiert Zeichenfolgen, die Steuerzeichen mit einem Hexadezimalwert unter 20 enthalten, als XML-Entitäten. Dies kann zu einem Problem mit einem Nicht-WCF-Client führen, wenn solche Daten an einen WCF-Dienst gesendet werden.

Erstellen einer DataContractSerializer-Instanz

Das Erstellen einer Instanz des Elements DataContractSerializer ist ein wichtiger Schritt. Nach der Konstruktion können Sie keine der Einstellungen ändern.

Angeben des Stammtyps

Der Stammtyp ist der Typ, von dem Instanzen serialisiert oder deserialisiert werden. Der DataContractSerializer hat viele Konstruktorüberladungen, aber es muss mindestens ein Stammtyp über den type-Parameter bereitgestellt werden.

Ein serialisierer, der für einen bestimmten Stammtyp erstellt wurde, kann nicht zum Serialisieren (oder Deserialisieren) eines anderen Typs verwendet werden, es sei denn, der Typ wird vom Stammtyp abgeleitet. Das folgende Beispiel zeigt zwei Klassen.

[DataContract]
public class Person
{
    // Code not shown.
}

[DataContract]
public class PurchaseOrder
{
    // Code not shown.
}
<DataContract()> _
Public Class Person
    ' Code not shown.
End Class

<DataContract()> _
Public Class PurchaseOrder
    ' Code not shown.
End Class

Dieser Code erstellt eine Instanz von DataContractSerializer, die nur zum Serialisieren oder Deserialisieren von Instanzen der Person-Klasse verwendet werden kann.

DataContractSerializer dcs = new DataContractSerializer(typeof(Person));
// This can now be used to serialize/deserialize Person but not PurchaseOrder.
Dim dcs As New DataContractSerializer(GetType(Person))
' This can now be used to serialize/deserialize Person but not PurchaseOrder.

Angeben bekannter Typen

Wenn Polymorphismus an den Serialisierungstypen beteiligt ist, die noch nicht mit dem KnownTypeAttribute Attribut oder einem anderen Mechanismus behandelt werden, muss eine Liste möglicher bekannter Typen mithilfe knownTypes des Parameters an den Konstruktor des Serialisierers übergeben werden. Weitere Informationen zu bekannten Typen finden Sie unter "Datenvertrag bekannte Typen".

Das folgende Beispiel zeigt eine Klasse, LibraryPatron, die eine Sammlung eines bestimmten Typs enthält, die LibraryItem. Die zweite Klasse definiert den LibraryItem Typ. Die dritte und vier Klassen (Book und Newspaper) erben von der LibraryItem Klasse.

[DataContract]
public class LibraryPatron
{
    [DataMember]
    public LibraryItem[] borrowedItems;
}
[DataContract]
public class LibraryItem
{
    // Code not shown.
}

[DataContract]
public class Book : LibraryItem
{
    // Code not shown.
}

[DataContract]
public class Newspaper : LibraryItem
{
    // Code not shown.
}
<DataContract()> _
Public Class LibraryPatron
    <DataMember()> _
    Public borrowedItems() As LibraryItem
End Class

<DataContract()> _
Public Class LibraryItem
    ' Code not shown.
End Class

<DataContract()> _
Public Class Book
    Inherits LibraryItem
    ' Code not shown.
End Class

<DataContract()> _
Public Class Newspaper
    Inherits LibraryItem
    ' Code not shown.
End Class

Der folgende Code erstellt eine Instanz des Serialisierers mithilfe des knownTypes Parameters.

// Create a serializer for the inherited types using the knownType parameter.
Type[] knownTypes = new Type[] { typeof(Book), typeof(Newspaper) };
DataContractSerializer dcs =
new DataContractSerializer(typeof(LibraryPatron), knownTypes);
// All types are known after construction.
' Create a serializer for the inherited types using the knownType parameter.
Dim knownTypes() As Type = {GetType(Book), GetType(Newspaper)}
Dim dcs As New DataContractSerializer(GetType(LibraryPatron), knownTypes)
' All types are known after construction.

Angeben des Standardstammnamens und des Namespaces

Wenn ein Objekt serialisiert wird, werden normalerweise der Standardname und der Namespace des äußersten XML-Elements entsprechend dem Datenvertragsnamen und -namespace bestimmt. Die Namen aller inneren Elemente werden aus Datenmitgliedsnamen bestimmt, und ihr Namensraum ist der Namensraum des Datenvertrags. Das folgende Beispiel legt Name und Namespace Werte in den Konstruktoren der Klassen DataContractAttribute und DataMemberAttribute fest.

[DataContract(Name = "PersonContract", Namespace = "http://schemas.contoso.com")]
public class Person2
{
    [DataMember(Name = "AddressMember")]
    public Address theAddress;
}

[DataContract(Name = "AddressContract", Namespace = "http://schemas.contoso.com")]
public class Address
{
    [DataMember(Name = "StreetMember")]
    public string street;
}
<DataContract(Name:="PersonContract", [Namespace]:="http://schemas.contoso.com")> _
Public Class Person2
    <DataMember(Name:="AddressMember")> _
    Public theAddress As Address
End Class

<DataContract(Name:="AddressContract", [Namespace]:="http://schemas.contoso.com")> _
Public Class Address
    <DataMember(Name:="StreetMember")> _
    Public street As String
End Class

Beim Serialisieren einer Instanz der Person Klasse wird XML ähnlich wie folgt erzeugt.

<PersonContract xmlns="http://schemas.contoso.com">  
  <AddressMember>  
    <StreetMember>123 Main Street</StreetMember>  
   </AddressMember>  
</PersonContract>  

Sie können jedoch den Standardnamen und den Namespace des Stammelements anpassen, indem Sie die Werte der rootName und rootNamespace Parameter an den DataContractSerializer Konstruktor übergeben. Beachten Sie, dass sich rootNamespace nicht auf den Namespace der enthaltenen Elemente auswirkt, die Datenmitgliedern entsprechen. Er wirkt sich nur auf den Namespace des äußersten Elements aus.

Diese Werte können als Zeichenfolgen oder Instanzen der XmlDictionaryString Klasse übergeben werden, um ihre Optimierung mithilfe des binär-XML-Formats zu ermöglichen.

Festlegen des maximal zulässigen Objektkontingents

Einige DataContractSerializer -Konstruktorüberladungen verfügen über den maxItemsInObjectGraph -Parameter. Dieser Parameter bestimmt die maximale Anzahl von Objekten, die der Serialisierer serialisiert oder deserialisiert, in einem einzelnen ReadObject Methodenaufruf. (Die Methode liest immer ein Stammobjekt, aber dieses Objekt enthält möglicherweise andere Objekte in seinen Datenmelementen. Diese Objekte haben möglicherweise andere Objekte usw.) Der Standardwert ist 65536. Beachten Sie, dass beim Serialisieren oder Deserialisieren von Arrays jeder Arrayeintrag als separates Objekt zählt. Beachten Sie außerdem, dass einige Objekte möglicherweise eine große Speicherdarstellung aufweisen. Daher reicht dieses Kontingent möglicherweise nicht aus, um einen Denial-of-Service-Angriff zu verhindern. Weitere Informationen finden Sie unter Sicherheitsüberlegungen für Daten. Wenn Sie dieses Kontingent über den Standardwert hinaus erhöhen müssen, ist es wichtig, dies sowohl beim Senden (Serialisieren) als auch beim Empfangen (Deserialisieren) zu tun, da es sowohl beim Lesen als auch beim Schreiben von Daten gilt.

Rundreisen

Ein Roundtrip tritt auf, wenn ein Objekt in einem Vorgang deserialisiert und neu serialisiert wird. Daher geht es von XML zu einer Objektinstanz und wieder zurück in einen XML-Datenstrom.

Einige DataContractSerializer Konstruktorüberladungen verfügen über einen ignoreExtensionDataObject Parameter, der standardmäßig auf false festgelegt ist. In diesem Standardmodus können Daten von einer neueren Version des Datenvertrags zu einer älteren Datenvertragsversion und wieder zurück zur neueren Version geschickt werden, ohne dass Datenverluste auftreten, sofern der Datenvertrag die IExtensibleDataObject -Schnittstelle implementiert. Nehmen wir beispielsweise an, Version 1 des Person -Datenvertrags enthält die Datenmember Name und PhoneNumber , und in Version 2 wurde der Member Nickname hinzugefügt. Wenn IExtensibleDataObject implementiert wird, werden beim Übertragen der Informationen von Version 2 zu Version 1 die Nickname Daten gespeichert und dann erneut übertragen, wenn die Daten erneut serialisiert werden. Daher gehen bei der Rückübertragung keine Daten verloren. Weitere Informationen finden Sie unter Forward-Compatible Datenverträge und Datenvertragsversionsverwaltung.

Sicherheits- und Schemagültigkeitsbedenken bei Roundtrips

Roundtrips können Sicherheitsauswirkungen haben. Das Deserialisieren und Speichern großer Mengen an überflüssigen Daten kann beispielsweise ein Sicherheitsrisiko darstellen. Es kann Sicherheitsbedenken geben, dass diese Daten erneut emittiert werden, dass es keine Möglichkeit gibt, zu überprüfen, insbesondere, wenn digitale Signaturen beteiligt sind. Im vorherigen Szenario könnte beispielsweise der Endpunkt der Version 1 einen Nickname Wert signieren, der schädliche Daten enthält. Schließlich kann es zu Schemagültigkeitsbedenken kommen: Ein Endpunkt möchte möglicherweise immer Daten ausgeben, die strikt den angegebenen Vertrag einhalten und keine zusätzlichen Werte. Im vorherigen Beispiel gibt der Vertrag des Endpunkts der Version 1 an, dass er nur Name ausgibt und PhoneNumber, und wenn die Schemaüberprüfung verwendet wird, führt die Ausgabe des Zusätzlichen Nickname Werts zu einem Fehler bei der Überprüfung.

Aktivieren und Deaktivieren von Roundtrips

Um Roundtrips zu deaktivieren, implementieren Sie die IExtensibleDataObject Schnittstelle nicht. Wenn Sie keine Kontrolle über die Typen haben, setzen Sie den Parameter ignoreExtensionDataObject auf true, um denselben Effekt zu erzielen.

Objektdiagramm-Erhaltung

Normalerweise kümmert sich der Serialisierer nicht um die Objektidentität, wie im folgenden Code.

[DataContract]
public class PurchaseOrder
{
    [DataMember]
    public Address billTo;
    [DataMember]
    public Address shipTo;
}

[DataContract]
public class Address
{
    [DataMember]
    public string street;
}
<DataContract()> _
Public Class PurchaseOrder

    <DataMember()> _
    Public billTo As Address

    <DataMember()> _
    Public shipTo As Address

End Class

<DataContract()> _
Public Class Address

    <DataMember()> _
    Public street As String

End Class

Der folgende Code erstellt eine Bestellung.

// Construct a purchase order:
Address adr = new Address();
adr.street = "123 Main St.";
PurchaseOrder po = new PurchaseOrder();
po.billTo = adr;
po.shipTo = adr;
' Construct a purchase order:
Dim adr As New Address()
adr.street = "123 Main St."
Dim po As New PurchaseOrder()
po.billTo = adr
po.shipTo = adr

Beachten Sie, dass billTo und shipTo Felder auf dieselbe Objektinstanz festgelegt sind. Der generierte XML-Code dupliziert jedoch die doppelten Informationen und sieht ähnlich wie im folgenden XML-Code aus.

<PurchaseOrder>  
  <billTo><street>123 Main St.</street></billTo>  
  <shipTo><street>123 Main St.</street></shipTo>  
</PurchaseOrder>  

Dieser Ansatz weist jedoch die folgenden Merkmale auf, die möglicherweise nicht erwünscht sind:

  • Leistung Replizieren von Daten ist ineffizient.

  • Zirkuläre Verweise. Wenn Objekte auf sich selbst verweisen, auch durch andere Objekte, führt die Serialisierung durch die Replikation zu einer endlosen Schleife. (Der Serialisierer löst ein SerializationException aus, wenn dies geschieht.)

  • Semantik. Manchmal ist es wichtig, die Tatsache zu bewahren, dass zwei Verweise auf dasselbe Objekt und nicht auf zwei identische Objekte bestehen.

Aus diesen Gründen verfügen einige DataContractSerializer Konstruktorüberladungen über einen preserveObjectReferences Parameter (der Standardwert ist false). Wenn dieser Parameter auf true festgelegt ist, wird eine spezielle Methode zur Kodierung von Objektverweisen angewendet, die nur WCF versteht. Bei Festlegung auf true, sieht das XML-Codebeispiel nun wie folgt aus.

<PurchaseOrder ser:id="1">  
  <billTo ser:id="2"><street ser:id="3">123 Main St.</street></billTo>  
  <shipTo ser:ref="2"/>  
</PurchaseOrder>  

Der Namespace "ser" bezieht sich auf den Standard-Serialisierungsnamespace, http://schemas.microsoft.com/2003/10/Serialization/. Jedes Datenstück wird nur einmal serialisiert und erhält eine ID-Nummer, und nachfolgende Verwendungen führen zu einem Verweis auf die bereits serialisierten Daten.

Von Bedeutung

Wenn sowohl die Attribute "id" als auch "ref" im Datenvertrag XMLElementvorhanden sind, wird das Attribut "ref" berücksichtigt, und das Attribut "id" wird ignoriert.

Es ist wichtig, die Einschränkungen dieses Modus zu verstehen:

  • Das XML, das der DataContractSerializer erzeugt, wenn der preserveObjectReferences -Parameter auf true festgelegt ist, kann von keiner anderen Technologie verarbeitet werden. Nur eine andere DataContractSerializer -Instanz, bei der der preserveObjectReferences -Parameter auch auf truefestgelegt ist, kann darauf zugreifen.

  • Für dieses Feature gibt es keine Unterstützung für Metadaten (Schema). Das erzeugte Schema ist nur für den Fall gültig, wenn preserveObjectReferences auf false gesetzt ist.

  • Dieses Feature kann dazu führen, dass der Serialisierungs- und Deserialisierungsprozess langsamer ausgeführt wird. Obwohl Daten nicht repliziert werden müssen, müssen in diesem Modus zusätzliche Objektvergleiche ausgeführt werden.

Vorsicht

Wenn der preserveObjectReferences Modus aktiviert ist, ist es besonders wichtig, den maxItemsInObjectGraph Wert auf das richtige Kontingent festzulegen. Aufgrund der Art und Weise, wie Arrays in diesem Modus behandelt werden, ist es für einen Angreifer einfach, eine kleine schädliche Nachricht zu erstellen, die zu einer großen Speicherauslastung führt, die nur durch das maxItemsInObjectGraph Kontingent begrenzt ist.

Angeben eines Surrogates für Datenverträge

Einige DataContractSerializer Konstruktor-Überladungen verfügen über einen dataContractSurrogate Parameter, der auf null festgelegt werden kann. Andernfalls können Sie sie verwenden, um eine Datenvertrags-Ersatzversion anzugeben, bei der es sich um einen Typ handelt, der die IDataContractSurrogate Schnittstelle implementiert. Anschließend können Sie die Schnittstelle verwenden, um den Serialisierungs- und Deserialisierungsprozess anzupassen. Weitere Informationen finden Sie unter Data Contract Surrogates.

Serialisierung

Die folgenden Informationen gelten für jede Klasse, die von der XmlObjectSerializer-Klasse erbt, einschließlich der DataContractSerializer-Klassen und NetDataContractSerializer-Klassen.

Einfache Serialisierung

Die einfachste Methode zum Serialisieren eines Objekts besteht darin, es an die WriteObject Methode zu übergeben. Es gibt drei Überladungen, jeweils eine zum Schreiben in ein Stream-Objekt, ein XmlWriter-Objekt oder ein XmlDictionaryWriter-Objekt. Bei der Stream-Überladung erfolgt die Ausgabe als XML in UTF-8-Codierung. Mit der XmlDictionaryWriter Überladung optimiert der Serialisierer seine Ausgabe für binäre XML.

Bei Verwendung der WriteObject Methode verwendet der Serializer den Standardnamen und namespace für das Wrapperelement und schreibt ihn zusammen mit dem Inhalt aus (siehe vorheriger Abschnitt "Angeben des Standardstammnamens und Namespaces").

Im folgenden Codebeispiel wird der Schreibvorgang mit XmlDictionaryWriterveranschaulicht.

Person p = new Person();
DataContractSerializer dcs =
    new DataContractSerializer(typeof(Person));
XmlDictionaryWriter xdw =
    XmlDictionaryWriter.CreateTextWriter(someStream,Encoding.UTF8 );
dcs.WriteObject(xdw, p);
Dim p As New Person()
Dim dcs As New DataContractSerializer(GetType(Person))
Dim xdw As XmlDictionaryWriter = _
    XmlDictionaryWriter.CreateTextWriter(someStream, Encoding.UTF8)
dcs.WriteObject(xdw, p)

Dies erzeugt XML ähnlich wie im folgenden.

<Person>  
  <Name>Jay Hamlin</Name>  
  <Address>123 Main St.</Address>  
</Person>  

Schrittweise Serialisierung

Verwenden Sie die Methoden WriteStartObject, WriteObjectContent und WriteEndObject, um das Endelement zu schreiben, den Objektinhalt zu schreiben und das Wrapperelement zu schließen.

Hinweis

Es sind keine Stream -Überladungen für diese Methoden verfügbar.

Diese schrittweise Serialisierung hat zwei häufige Verwendungsmöglichkeiten. Eine ist das Einfügen von Inhalten wie Attributen oder Kommentaren zwischen WriteStartObject und WriteObjectContent, wie im folgenden Beispiel gezeigt.

dcs.WriteStartObject(xdw, p);
xdw.WriteAttributeString("serializedBy", "myCode");
dcs.WriteObjectContent(xdw, p);
dcs.WriteEndObject(xdw);
dcs.WriteStartObject(xdw, p)
xdw.WriteAttributeString("serializedBy", "myCode")
dcs.WriteObjectContent(xdw, p)
dcs.WriteEndObject(xdw)

Dies erzeugt XML ähnlich wie im folgenden.

<Person serializedBy="myCode">  
  <Name>Jay Hamlin</Name>  
  <Address>123 Main St.</Address>  
</Person>  

Eine weitere häufige Verwendung besteht darin, die Verwendung WriteStartObject und WriteEndObject vollständig zu vermeiden und ein eigenes benutzerdefiniertes Wrapperelement zu schreiben (oder sogar das Schreiben eines Wrappers vollständig zu überspringen), wie im folgenden Code gezeigt.

xdw.WriteStartElement("MyCustomWrapper");
dcs.WriteObjectContent(xdw, p);
xdw.WriteEndElement();
xdw.WriteStartElement("MyCustomWrapper")
dcs.WriteObjectContent(xdw, p)
xdw.WriteEndElement()

Dies erzeugt XML ähnlich wie im folgenden.

<MyCustomWrapper>  
  <Name>Jay Hamlin</Name>  
  <Address>123 Main St.</Address>  
</MyCustomWrapper>  

Hinweis

Eine schrittweise Serialisierung kann zu schemaungültigem XML führen.

Deserialisierung

Die folgenden Informationen gelten für jede Klasse, die von der XmlObjectSerializer-Klasse erbt, einschließlich der DataContractSerializer-Klassen und NetDataContractSerializer-Klassen.

Die einfachste Methode zum Deserialisieren eines Objekts besteht darin, eine der ReadObject Methodenüberladungen aufzurufen. Es sind drei Überladungen verfügbar, jeweils eine zum Lesen mit einem XmlDictionaryReader-Objekt, einem XmlReader-Objekt oder einem Stream-Objekt. Beachten Sie, dass die Stream Überladung einen Text XmlDictionaryReader erstellt, der nicht durch Kontingente geschützt ist und nur zum Lesen vertrauenswürdiger Daten verwendet werden sollte.

Beachten Sie außerdem, dass das Objekt, das die ReadObject-Methode zurückgibt, in den entsprechenden Typ umgewandelt werden muss.

Mit dem folgenden Code wird eine Instanz der DataContractSerializer und einer XmlDictionaryReaderInstanz erstellt. Anschließend wird eine Person Instanz deserialisiert.

DataContractSerializer dcs = new DataContractSerializer(typeof(Person));
FileStream fs = new FileStream(path, FileMode.Open);
XmlDictionaryReader reader =
XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());

Person p = (Person)dcs.ReadObject(reader);
Dim dcs As New DataContractSerializer(GetType(Person))
Dim fs As New FileStream(path, FileMode.Open)
Dim reader As XmlDictionaryReader = _
   XmlDictionaryReader.CreateTextReader(fs, New XmlDictionaryReaderQuotas())

Dim p As Person = CType(dcs.ReadObject(reader), Person)

Positionieren Sie vor dem Aufrufen der ReadObject Methode den XML-Reader im Wrapperelement oder auf einem Nicht-Inhaltsknoten, der dem Wrapperelement vorausgeht. Sie können dies tun, indem Sie die Read Methode der XmlReader oder deren Ableitung aufrufen und die NodeType, wie im folgenden Code gezeigt, testen.

DataContractSerializer ser = new DataContractSerializer(typeof(Person),
"Customer", @"http://www.contoso.com");
FileStream fs = new FileStream(path, FileMode.Open);
XmlDictionaryReader reader =
XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
while (reader.Read())
{
    switch (reader.NodeType)
    {
        case XmlNodeType.Element:
            if (ser.IsStartObject(reader))
            {
                Console.WriteLine("Found the element");
                Person p = (Person)ser.ReadObject(reader);
                Console.WriteLine($"{p.Name} {p.Address}    id:{2}");
            }
            Console.WriteLine(reader.Name);
            break;
    }
}
Dim ser As New DataContractSerializer(GetType(Person), "Customer", "http://www.contoso.com")
Dim fs As New FileStream(path, FileMode.Open)
Dim reader As XmlDictionaryReader = XmlDictionaryReader.CreateTextReader(fs, New XmlDictionaryReaderQuotas())

While reader.Read()
    Select Case reader.NodeType
        Case XmlNodeType.Element
            If ser.IsStartObject(reader) Then
                Console.WriteLine("Found the element")
                Dim p As Person = CType(ser.ReadObject(reader), Person)
                Console.WriteLine("{0} {1}", _
                                   p.Name, p.Address)
            End If
            Console.WriteLine(reader.Name)
    End Select
End While

Beachten Sie, dass Sie Attribute für dieses Wrapper-Element lesen können, bevor Sie das Leserobjekt an ReadObject weitergeben.

Bei Verwendung einer der einfachen ReadObject Überladungen sucht der Deserializer im Wrapperelement nach dem Standardnamen und namespace (siehe vorherigen Abschnitt "Angeben des Standardstammnamens und Namespaces"), und löst eine Ausnahme aus, wenn ein unbekanntes Element gefunden wird. Im vorherigen Beispiel wird das <Person> Wrapperelement erwartet. Die IsStartObject Methode wird aufgerufen, um zu überprüfen, ob der Leser in einem Element positioniert ist, das wie erwartet benannt wird.

Es gibt eine Möglichkeit, diese Wrapperelementnamensprüfung zu deaktivieren; einige Überladungen der ReadObject Methode verwenden den booleschen Parameter verifyObjectName, der standardmäßig auf festgelegt true ist. Bei Festlegung auf false, wird der Name und der Namespace des Wrapperelements ignoriert. Dies ist hilfreich beim Lesen von XML, das mithilfe des zuvor beschriebenen Schritt-für-Schritt-Serialisierungsmechanismus geschrieben wurde.

Verwenden des NetDataContractSerializers

Der Hauptunterschied zwischen DataContractSerializer und NetDataContractSerializer besteht darin, dass DataContractSerializer Datenvertragsnamen verwendet, während NetDataContractSerializer vollständige Assembly- und Typnamen des .NET-Frameworks in der serialisierten XML ausgibt. Dies bedeutet, dass die gleichen Typen zwischen den Serialisierungs- und Deserialisierungsendpunkten gemeinsam verwendet werden müssen. Dies bedeutet, dass der bekannte Typenmechanismus im Zusammenhang mit NetDataContractSerializer nicht erforderlich ist, da die genauen Typen, die deserialisiert werden sollen, immer bekannt sind.

Es können jedoch mehrere Probleme auftreten:

  • Sicherheit: Jeder Typ, der in dem XML-Code gefunden wird, der deserialisiert wird, wird geladen. Dies kann ausgenutzt werden, um das Laden bösartiger Typen zu erzwingen. NetDataContractSerializer sollte nur dann für nicht vertrauenswürdige Daten eingesetzt werden, wenn ein Serialisierungsbinder verwendet wird (über die Binder -Eigenschaft oder einen Konstruktorparameter). Der Binder erlaubt, dass nur sichere Typen geladen werden. Der Binder-Mechanismus ist identisch mit demjenigen, den die Typen im System.Runtime.Serialization-Namespace verwenden.

  • Versionskontrolle. Die Verwendung vollständiger Typ- und Assemblynamen im XML-Code schränkt stark ein, wie Typen versionsgesteuert werden können. Folgendes kann nicht geändert werden: Typnamen, Namespaces, Assemblynamen und Assemblyversionen. Durch Setzen der AssemblyFormat-Eigenschaft oder des Konstruktorparameters auf Simple anstelle des Standardwerts Full werden Änderungen der Assemblyversion zugelassen, jedoch nicht für generische Parametertypen.

  • Interoperabilität. Da .NET Framework-Typ- und Assemblynamen in xml enthalten sind, können andere Plattformen als .NET Framework nicht auf die resultierenden Daten zugreifen.

  • Leistung Durch das Schreiben der Typ- und Assemblynamen wird die Größe des resultierenden XML-Codes erheblich erhöht.

Dieser Mechanismus ähnelt der binären oder SOAP-Serialisierung, die von .NET Framework-Remoting verwendet wird (insbesondere die BinaryFormatter und die SoapFormatter).

Die Verwendung von NetDataContractSerializer ähnelt der Verwendung von DataContractSerializer, mit den folgenden Unterschieden:

  • Die Konstruktoren erfordern keine Angabe des Stammtyps. Sie können jeden beliebigen Typ mit derselben Instanz von NetDataContractSerializer serialisieren.

  • Die Konstruktoren akzeptieren keine Liste bekannter Typen. Der bekannte Typenmechanismus ist nicht erforderlich, wenn Typnamen in den XML-Code serialisiert werden.

  • Die Konstruktoren akzeptieren kein Datenvertragssurrogat. Stattdessen akzeptieren sie einen ISurrogateSelector Parameter namens surrogateSelector (der der SurrogateSelector Eigenschaft zugeordnet ist). Dies ist ein veralteter Ersatzmechanismus.

  • Die Konstruktoren akzeptieren einen Parameter namens assemblyFormat vom FormatterAssemblyStyle , welcher der AssemblyFormat -Eigenschaft zugeordnet wird. Wie bereits erwähnt, kann dies verwendet werden, um die Versionsverwaltungsfunktionen des Serialisierers zu verbessern. Dies ist identisch mit dem Mechanismus in binärer FormatterAssemblyStyle oder SOAP-Serialisierung.

  • Die Konstruktoren akzeptieren einen StreamingContext -Parameter namens context , welcher der Context -Eigenschaft zugeordnet wird. Sie können dies verwenden, um Informationen an Typen zu übergeben, die serialisiert werden. Diese Art der Verwendung entspricht dem StreamingContext -Mechanismus, der in anderen System.Runtime.Serialization -Klassen verwendet wird.

  • Die Serialize- und Deserialize-Methoden sind Aliase für die WriteObject- und ReadObject-Methoden. Diese sind vorhanden, um ein konsistentes Programmiermodell mit binärer oder SOAP-Serialisierung bereitzustellen.

Weitere Informationen zu diesen Features finden Sie unter Binäre Serialisierung.

Die XML-Formate, die NetDataContractSerializer und DataContractSerializer verwenden, sind normalerweise nicht kompatibel. Das heißt, der Versuch, mit einem dieser Serialisierer zu serialisieren und mit dem anderen zu deserialisieren, ist kein unterstütztes Szenario.

Beachten Sie außerdem, dass der NetDataContractSerializer nicht den vollständigen .NET Framework-Typ- und Assemblynamen für jeden Knoten im Objektgraphen ausgibt. Sie gibt diese Informationen nur dort aus, wo sie mehrdeutig ist. Das heißt, er gibt auf der Stammobjektebene und für alle polymorphen Fälle aus.

Siehe auch