Freigeben über


Eigenständige JSON-Serialisierung mit DataContractJsonSerializer

Hinweis

In diesem Artikel geht es um DataContractJsonSerializer. Für die meisten Szenarien, die json serialisieren und deserialisieren, empfehlen wir die APIs im System.Text.Json-Namespace.

JSON (JavaScript Object Notation) ist ein Datenformat, das speziell für die Verwendung durch JavaScript-Code entwickelt wurde, der auf Webseiten im Browser ausgeführt wird. Es handelt sich um das Standarddatenformat, das von ASP.NET AJAX-Diensten verwendet wird, die in Windows Communication Foundation (WCF) erstellt wurden.

Dieses Format kann auch beim Erstellen von AJAX-Diensten verwendet werden, ohne in ASP.NET zu integrieren . In diesem Fall ist XML die Standardeinstellung, JSON kann jedoch ausgewählt werden.

Obwohl Sie keinen AJAX-Dienst erstellen, können Sie mit DataContractJsonSerializer .NET-Objekte direkt in JSON-Daten serialisieren und solche Daten wieder in Instanzen von .NET-Typen deserialisieren, wenn Sie JSON-Unterstützung benötigen. Eine Beschreibung dazu finden Sie unter How to: Serialize and Deserialize JSON Data.

Beim Arbeiten mit JSON werden dieselben .NET-Typen unterstützt wie bei der DataContractSerializer, mit einigen Ausnahmen. Eine Liste der unterstützten Typen finden Sie unter "Vom Datenvertrags serializer unterstützte Typen". Dazu gehören die meisten Grundtypen, die meisten Array- und Sammlungstypen sowie komplexe Typen, die DataContractAttribute und DataMemberAttribute verwenden.

Zuordnen von .NET-Typen zu JSON-Typen

Die folgende Tabelle zeigt die Korrespondenz zwischen .NET-Typen und JSON/JavaScript-Typen, wenn sie durch Serialisierungs- und Deserialisierungsprozeduren zugeordnet werden.

.NET-Typen JSON/JavaScript Hinweise
Alle numerischen Typen, zum Beispiel Int32, Decimal oder Double Nummer Spezielle Werte wie Double.NaN, Double.PositiveInfinity und Double.NegativeInfinity werden nicht unterstützt und führen zu ungültigen JSON-Code.
Enum Nummer Weitere Informationen finden Sie weiter unten in diesem Artikel unter "Enumerationen und JSON".
Boolean Boolescher Typ (Boolean)
String, Char Schnur
TimeSpan, GuidUri Schnur Das Format dieser Typen in JSON ist identisch mit xml (im Wesentlichen zeitspanne im ISO 8601 Duration Format, GUID im Format "12345678-ABCD-ABCD-ABCD-ABCD-1234567890AB" und URI in seiner natürlichen Zeichenfolgenform wie "http://www.example.com"). Genaue Informationen finden Sie unter Data Contract Schema Reference.
XmlQualifiedName Schnur Das Format lautet "name:namespace" (alles vor dem ersten Doppelpunkt ist der Name). Der Name oder der Namespace kann fehlen. Wenn kein Namespace angegeben wird, kann auch der Doppelpunkt weggelassen werden.
Array vom Typ Byte Array von Zahlen Jede Zahl stellt den Wert eines Byte dar.
DateTime DateTime oder Zeichenfolge Siehe Datumsangaben/Uhrzeiten und JSON weiter unten in diesem Artikel.
DateTimeOffset Komplexer Typ Siehe Datumsangaben/Uhrzeiten und JSON weiter unten in diesem Artikel.
XML- und ADO.NET typen (XmlElement,

XElement. Arrays von XmlNode,

ISerializable,

DataSet).
Schnur Weitere Informationen finden Sie im Abschnitt "XML-Typen und JSON" dieses Artikels.
DBNull Leerer komplexer Typ --
Sammlungen, Wörterbücher und Arrays Anordnung Weitere Informationen finden Sie im Abschnitt "Sammlungen", "Wörterbücher" und "Arrays" dieses Themas.
Komplexe Typen (mit angewendetem DataContractAttribute oder SerializableAttribute) Komplexer Typ Datenmitglieder werden Mitglieder des komplexen JavaScript-Typs.
Komplexe Typen, die die ISerializable Schnittstelle implementieren) Komplexer Typ Identisch mit anderen komplexen Typen, aber einige ISerializable Typen werden nicht unterstützt – siehe ISerializable Support.
Null Wert für einen beliebigen Typ Null Nullable-Werttypen werden ebenfalls unterstützt und JSON auf die gleiche Weise zugeordnet wie nicht-nullfähige Werttypen.

Enumerationen und JSON

Werte von Aufzählungselementen werden in JSON als Zahlen behandelt, was sich von ihrer Behandlung in Datenverträgen unterscheidet, wo sie als Mitgliedsnamen enthalten sind. Weitere Informationen zur Datenvertragsbehandlung finden Sie unter Enumerationstypen in Datenverträgen.

  • Wenn Sie z. B. über public enum Color {red, green, blue, yellow, pink} verfügen, ergibt das Serialisieren von yellow die Zahl 3 und nicht den String "gelb".

  • Alle enum-Member sind serialisierbar. Die Attribute EnumMemberAttribute und NonSerializedAttribute werden bei Verwendung ignoriert.

  • Es ist möglich, einen nicht vorhandenen enum Wert zu deserialisieren; zum Beispiel kann der Wert 87 in das frühere Color-Enum deserialisiert werden, obwohl kein entsprechender Farbname definiert ist.

  • Eine Kennzeichnung enum ist nicht besonders und wird genauso behandelt wie jede andere enum.

Datums-/Uhrzeitangaben und JSON

Das JSON-Format unterstützt datums- und uhrzeitangaben nicht direkt. Sie werden jedoch sehr häufig verwendet, und ASP.NET AJAX bietet spezielle Unterstützung für diese Typen. Bei Verwendung ASP.NET AJAX-Proxys entspricht der DateTime Typ in .NET vollständig dem DateTime Typ in JavaScript.

  • Wenn ASP.NET nicht verwendet wird, wird ein DateTime Typ in JSON als Zeichenfolge mit einem speziellen Format dargestellt, das im Abschnitt "Erweiterte Informationen" dieses Themas beschrieben wird.

  • DateTimeOffset wird in JSON als komplexer Typ dargestellt: {"DateTime":d ateTime,"OffsetMinutes":offsetMinutes}. Der offsetMinutes-Member gibt den mit der Position des Ereignisses von Interesse verbundenen Ortszeitoffset zur GMT (Greenwich Mean Time) an. GMT wird jetzt auch als UTC (Coordinated Universal Time) bezeichnet. Das dateTime-Element stellt die Zeit dar, wann das Ereignis von Interesse aufgetreten ist (es wird erneut zu einem DateTime in JavaScript, wenn ASP.NET AJAX verwendet wird, und zu einer Zeichenfolge, wenn nicht). Bei der Serialisierung wird das dateTime Element immer in GMT serialisiert. Wenn beispielsweise die Uhrzeit 3:00 AM in der Zeitzone von New York beschrieben wird, dann enthält dateTime die Zeitangabe "8:00 AM" und offsetMinutes den Wert "300" (minus 300 Minuten oder 5 Stunden gegenüber GMT).

    Hinweis

    DateTime und DateTimeOffset Objekte, wenn sie in JSON serialisiert werden, behalten nur Informationen in Millisekunden genauigkeit bei. Unter millisekundenwerte (Mikro-/Nanosekunden) gehen während der Serialisierung verloren.

XML-Typen und JSON

XML-Typen werden zu JSON-Zeichenfolgen.

  • Wenn z. B. ein Datenmitglied "q" vom Typ "XElement" <abc/> enthält, lautet der JSON-Code {"q":"<abc/>"}.

  • Es gibt einige spezielle Regeln, die angeben, wie XML eingeschlossen wird. Weitere Informationen finden Sie im Abschnitt "Erweiterte Informationen" weiter unten in diesem Artikel.

  • Wenn Sie ASP.NET AJAX verwenden und keine Zeichenfolgen in JavaScript verwenden möchten, sondern das XML-DOM bevorzugen, legen Sie die Eigenschaft ResponseFormat auf XML auf WebGetAttribute oder die Eigenschaft ResponseFormat auf XML auf WebInvokeAttribute.

Sammlungen, Wörterbücher und Arrays

Alle Auflistungen, Wörterbücher und Arrays werden in JSON als Arrays dargestellt.

  • Jede Anpassung, die dies CollectionDataContractAttribute verwendet, wird in der JSON-Darstellung ignoriert.

  • Wörterbücher sind keine Möglichkeit, direkt mit JSON zu arbeiten. Dictionary<string,object> wird in WCF möglicherweise nicht auf die gleiche Weise unterstützt, wie es beim Arbeiten mit anderen JSON-Technologien erwartet wird. Wenn "abc" beispielsweise "xyz" zugeordnet ist und "def" in einem Wörterbuch 42 zugeordnet ist, ist die JSON-Darstellung nicht {"abc":"xyz","def":42}, sondern [{"Key":"abc","Value":"xyz"},{"Key":"def","Value":42}] stattdessen.

  • Wenn Sie mit JSON direkt arbeiten möchten (dynamischer Zugriff auf Schlüssel und Werte, ohne einen starren Vertrag zu definieren), haben Sie mehrere Optionen:

    • Erwägen Sie die Verwendung des Beispiels zur schwach typierten JSON-Serialisierung (AJAX).

    • Erwägen Sie die Verwendung der ISerializable Schnittstellen- und Deserialisierungskonstruktoren – mit diesen beiden Mechanismen können Sie auf JSON-Schlüssel-Wert-Paare für Serialisierung bzw. Deserialisierung zugreifen, sie funktionieren jedoch nicht in Umgebungen mit eingeschränktem Vertrauen.

    • Erwägen Sie die Arbeit mit der Zuordnung zwischen JSON und XML , anstatt einen Serialisierer zu verwenden.

    • Polymorphismus im Kontext der Serialisierung bezieht sich auf die Fähigkeit, einen abgeleiteten Typ zu serialisieren, in dem sein Basistyp erwartet wird. Es gibt spezielle JSON-spezifische Regeln, wenn Auflistungen polymorph verwendet werden, wenn z. B. eine Auflistung einem Object zugewiesen wird. Dieses Problem wird weiter unten in diesem Artikel im Abschnitt "Erweiterte Informationen" ausführlicher behandelt.

Zusätzliche Details

Reihenfolge der Datenmember

Die Reihenfolge der Datenmmber ist bei der Verwendung von JSON nicht wichtig. Selbst wenn Order festgelegt ist, können JSON-Daten in beliebiger Reihenfolge deserialisiert werden.

JSON-Typen

Der JSON-Typ muss nicht mit der vorherigen Tabelle zur Deserialisierung übereinstimmen. Normalerweise wird ein Int einer JSON-Nummer zugeordnet, aber es kann auch erfolgreich aus einer JSON-Zeichenfolge deserialisiert werden, solange diese Zeichenfolge eine gültige Zahl enthält. Das heißt, sowohl {"q":42} als auch {"q":"42"} sind gültig, wenn ein Int Datenelement namens "q" vorhanden ist.

Polymorphismus

Die polymorphe Serialisierung besteht aus der Fähigkeit, einen abgeleiteten Typ zu serialisieren, in dem der Basistyp erwartet wird. Dies wird für die JSON-Serialisierung durch WCF unterstützt, die mit der Unterstützung der XML-Serialisierung vergleichbar ist. Beispielsweise können Sie MyDerivedType serialisieren, wo MyBaseType erwartet wird, oder Int serialisieren, wo Object erwartet wird.

Typinformationen gehen möglicherweise verloren, wenn sie einen abgeleiteten Typ deserialisieren, wenn der Basistyp erwartet wird, es sei denn, Sie deserialisieren einen komplexen Typ. Wenn beispielsweise Uri an der Object erwarteten Stelle serialisiert wird, führt sie zu einer JSON-Zeichenfolge. Wenn diese Zeichenfolge dann zurück in Object deserialisiert wird, wird ein .NET String zurückgegeben. Der Deserializer weiß nicht, dass die Zeichenfolge anfangs vom Typ Uriwar. Im Allgemeinen werden beim Erwarten von Object alle JSON-Zeichenfolgen als .NET-Zeichenfolgen deserialisiert, und alle JSON-Arrays, die verwendet werden, um .NET-Sammlungen, -Wörterbücher und -Arrays zu serialisieren, werden als .NET Array vom Typ Object deserialisiert, unabhängig davon, welcher tatsächliche ursprüngliche Typ vorlag. Der JSON-Typ boolean wird dem .NET-Typ Boolean zugeordnet. Wenn jedoch ein Object erwartet wird, werden JSON-Zahlen entweder als .NET Int32, Decimal oder Double deserialisiert, wobei der jeweils am besten geeignete Typ automatisch ausgewählt wird.

Beim Deserialisieren in einen Schnittstellentyp verhält sich die DataContractJsonSerializer so, als ob der deklarierte Typ ein Objekt wäre.

Bei der Arbeit mit Ihren eigenen Basis- und abgeleiteten Typen ist es normalerweise erforderlich, KnownTypeAttribute oder ServiceKnownTypeAttribute beziehungsweise einen entsprechenden Mechanismus zu verwenden. Wenn Sie beispielsweise einen Vorgang haben, der einen Animal Rückgabewert aufweist und tatsächlich eine Instanz von Cat (abgeleitet von Animal) zurückgibt, sollten Sie entweder den KnownTypeAttribute Typ auf den Animal anwenden oder den ServiceKnownTypeAttribute auf den Vorgang anwenden und den Cat Typ in diesen Attributen angeben. Weitere Informationen finden Sie unter Datenvertrag: Bekannte Typen.

Ausführliche Informationen dazu, wie die polymorphe Serialisierung funktioniert, und eine Erläuterung einiger einschränkungen, die bei der Verwendung beachtet werden müssen, finden Sie weiter unten in diesem Artikel im Abschnitt "Erweiterte Informationen".

Versionsverwaltung

Die Datenvertragsversionierungsfunktionen, einschließlich der IExtensibleDataObject Schnittstelle, werden in JSON vollständig unterstützt. Außerdem kann es in den meisten Fällen möglich sein, einen Typ in einem Format (z. B. XML) zu deserialisieren und ihn dann in ein anderes Format (z. B. JSON) zu serialisieren, während die Daten in IExtensibleDataObject weiterhin beibehalten werden. Weitere Informationen finden Sie unter Forward-Compatible Datenverträge. Denken Sie daran, dass JSON nicht sortiert ist, sodass alle Bestellinformationen verloren gegangen sind. Darüber hinaus unterstützt JSON nicht mehrere Schlüssel-Wert-Paare mit demselben Schlüsselnamen. Schließlich sind alle Vorgänge IExtensibleDataObject inhärent polymorph - d. h. ihr abgeleiteter Typ wird dem Basistyp für alle Typen zugewiesen Object.

JSON in URLs

Wenn Sie ASP.NET AJAX-Endpunkte mit dem HTTP GET-Verb (mit dem WebGetAttribute Attribut) verwenden, werden eingehende Parameter in der Anforderungs-URL anstelle des Nachrichtentexts angezeigt. JSON wird auch in der Anforderungs-URL unterstützt. Wenn Sie also einen Vorgang haben, der eine Int sogenannte "Zahl" und einen Person komplexen Typ namens "p" akzeptiert, kann die URL der folgenden URL ähneln.

http://example.com/myservice.svc/MyOperation?number=7&p={"name":"John","age":42}

Wenn Sie ein ASP.NET AJAX Script Manager-Steuerelement und proxy verwenden, um den Dienst aufzurufen, wird diese URL automatisch vom Proxy generiert und wird nicht angezeigt. JSON kann nicht in URLs auf non-ASP.NET AJAX-Endpunkten verwendet werden.

Erweiterte Informationen

ISerializable-Unterstützung

Unterstützte und nicht unterstützte ISerializable-Typen

Im Allgemeinen werden Typen, die die ISerializable Schnittstelle implementieren, beim Serialisieren/Deserialisieren von JSON vollständig unterstützt. Einige dieser Typen (einschließlich einiger .NET Framework-Typen) werden jedoch so implementiert, dass die JSON-spezifischen Serialisierungsaspekte dazu führen, dass sie nicht ordnungsgemäß deserialisiert werden:

  • Mit ISerializable ist der Typ einzelner Datenmitglieder nie im Voraus bekannt. Dies führt zu einer polymorphen Situation, die der Deserialisierung von Typen in ein Objekt ähnelt. Wie bereits erwähnt, kann dies zu Verlust von Typinformationen in JSON führen. Ein Typ z. B., der eine enum in seiner ISerializable-Implementierung serialisiert und versucht, den erhaltenen Wert direkt wieder zurück in eine enum zu deserialisieren, wird ohne die korrekten Umwandlungen fehlschlagen, weil eine enum in JSON als Zahl serialisiert wird und JSON-Zahlen in die integrierten numerischen .NET-Typen (Int32, Decimal oder Double) deserialisiert werden. Die Tatsache, dass die Zahl früher ein enum Wert war, geht verloren.

  • Ein ISerializable Typ, der von einer bestimmten Reihenfolge der Deserialisierung im Konstruktor der Deserialisierung abhängt, kann auch einige JSON-Daten nicht deserialisieren, da die meisten JSON-Serialisierer keine bestimmte Reihenfolge garantieren.

Fabriktypen

Während die IObjectReference-Schnittstelle allgemein in JSON unterstützt wird, werden Typen, die die Funktion „Factorytyp“ benötigen (die Rückgabe eines anderen Typs von GetRealObject(StreamingContext) als den Typ, der die Schnittstelle implementiert) nicht unterstützt.

DateTime-Übertragungsformat

DateTime Werte werden als JSON-Zeichenfolgen in Form von "/Date(70000+0500)/" angezeigt, wobei die erste Zahl (7000000 in dem angegebenen Beispiel) die Anzahl der Millisekunden in der GMT-Zeitzone ist, normale (nicht sommerfreie) Zeit seit Mitternacht, dem 1. Januar 1970. Die Zahl kann negativ sein, um frühere Zeiten darzustellen. Der Teil, der aus "+0500" im Beispiel besteht, ist optional und gibt an, dass die Uhrzeit der Local Art ist , d. h. in die lokale Zeitzone bei der Deserialisierung konvertiert werden soll. Wenn sie nicht vorhanden ist, wird die Zeit deserialisiert als Utc. Die tatsächliche Zahl ("0500" in diesem Beispiel) und das zugehörige Zeichen (+oder -) werden ignoriert.

Bei der Serialisierung werden DateTime-, Local- und Unspecified-Zeitangaben mit einem Offset und Utc-Zeitangaben ohne Offset geschrieben.

Der ASP.NET AJAX-Client-JavaScript-Code konvertiert diese Zeichenfolgen automatisch in JavaScript-Instanzen DateTime . Wenn es andere Zeichenfolgen mit einer ähnlichen Form gibt, die nicht vom Typ DateTime in .NET ist, werden sie ebenfalls konvertiert.

Die Konvertierung wird nur dann vorgenommen, wenn die Schrägstriche (/) mit Escapezeichen versehen sind (also die JSON-Zeichenfolge wie „\/Date(700000+0500)\/“ aussieht). Aus diesem Grund versieht der JSON-Encoder von WCF (aktiviert durch WebHttpBinding) Schrägstriche immer mit Escapezeichen.

XML in JSON-Zeichenfolgen

XmlElement

Der Typ XmlElement wird ohne Einbindung serialisiert wie er ist. Beispielsweise wird das Datenmitglied "x" des Typs XmlElement, das <abc/> enthält, wie folgt dargestellt:

{"x":"<abc/>"}

XmlNode-Arrays

Array Objekte vom Typ XmlNode werden in ein Element namens ArrayOfXmlNode im Standarddatenvertragsnamespace für den Typ eingeschlossen. Wenn "x" ein Array ist, das den Attributknoten "N" im Namespace "ns" enthält, der "Wert" und einen leeren Elementknoten "M" enthält, lautet die Darstellung wie folgt.

{"x":"<ArrayOfXmlNode xmlns=\"http://schemas.datacontract.org/2004/07/System.Xml\" a:N=\"value\" xmlns:a=\"ns\"><M/></ArrayOfXmlNode>"}

Attribute im leeren Namespace am Anfang von XmlNode-Arrays (vor anderen Elementen) werden nicht unterstützt.

IXmlSerializable-Typen, einschließlich XElement- und DataSet-Typen

ISerializable Typen unterteilen sich in "Inhaltstypen", "DataSet-Typen" und "Elementtypen". Definitionen dieser Typen finden Sie unter XML und ADO.NET Typen in Datenverträgen.

Die Typen "Content" und "DataSet" werden ähnlich wie Array objekte des XmlNode vorherigen Abschnitts serialisiert. Der Name und der Namespace des Elements, in dem sie eingeschlossen sind, entsprechen dem Datenvertragsnamen und Namespace des betreffenden Typs.

"Element"-Typen wie XElement werden serialisiert, ähnlich wie XmlElement zuvor in diesem Artikel beschrieben.

Polymorphismus

Beibehalten von Typinformationen

Wie bereits erwähnt, wird Polymorphismus in JSON mit einigen Einschränkungen unterstützt. JavaScript ist eine schwach typierte Sprache und Typidentität ist normalerweise kein Problem. Wenn Sie jedoch JSON verwenden, um zwischen einem stark typierten System (.NET) und einem schwach typierten System (JavaScript) zu kommunizieren, ist es nützlich, die Typidentität beizubehalten. Beispielsweise werden Typen mit Datenvertragsnamen "Square" und "Circle" von einem Typ mit dem Datenvertragsnamen "Shape" abgeleitet. Wenn "Circle" von .NET an JavaScript gesendet wird und später an eine .NET-Methode zurückgegeben wird, die "Shape" erwartet, ist es nützlich, dass das betreffende Objekt ursprünglich ein "Circle" war - andernfalls können alle Für den abgeleiteten Typ spezifischen Informationen (z. B. "Radius"-Datenmemm "Circle") verloren gehen.

Um die Typidentität beizubehalten, kann beim Serialisieren komplexer Typen in JSON ein "Typhinweis" hinzugefügt werden, und der Deserializer erkennt den Hinweis und fungiert entsprechend. Der "Typhinweis" ist ein JSON-Schlüssel-Wert-Paar mit dem Schlüsselnamen "__type" (zwei Unterstriche gefolgt vom Wort "typ"). Der Wert ist eine JSON-Zeichenfolge des Formulars "DataContractName:DataContractNamespace" (alles bis zum ersten Doppelpunkt ist der Name). Im vorherigen Beispiel kann "Circle" wie folgt serialisiert werden.

{"__type":"Circle:http://example.com/myNamespace","x":50,"y":70,"radius":10}

Der Typhinweis ähnelt stark dem xsi:type-Attribut, das vom XML Schema Instance-Standard definiert ist und beim Serialisieren/Deserialisieren von XML verwendet wird.

Datenmitglieder mit dem Namen "__type" sind aufgrund potenzieller Konflikte mit dem Typhinweis verboten.

Reduzieren der Größe von Typhinweisen

Um die Größe von JSON-Nachrichten zu verringern, wird das Standardpräfix für den Datenvertragsnamespace (http://schemas.datacontract.org/2004/07/) durch das Zeichen "#" ersetzt. (Damit diese Ersetzung wieder rückgängig gemacht werden kann, gilt eine Regel für die Verwendung von Escapezeichen: Beginnt der Namespace mit den Zeichen "#" oder "\", werden diese Zeichen zusammen mit einem "\"-Zeichen angehängt). Wenn "Circle" also ein Typ im .NET-Namespace "MyApp.Shapes" ist, ist der Standarddatenvertragsnamespace http://schemas.datacontract.org/2004/07/MyApp. Formen und die JSON-Darstellung sind wie folgt.

{"__type":"Circle:#MyApp.Shapes","x":50,"y":70,"radius":10}

Bei der Deserialisierung werden sowohl die verkürzten (#MyApp.Shapes) als auch die vollständigen (http://schemas.datacontract.org/2004/07/MyApp.Shapes) Namen erkannt.

Typhinweisposition in JSON-Objekten

Beachten Sie, dass der Typhinweis zuerst in der JSON-Darstellung angezeigt werden muss. Dies ist der einzige Fall, wenn die Reihenfolge von Schlüssel-Wert-Paaren bei der JSON-Verarbeitung wichtig ist. Das folgende Beispiel ist keine gültige Methode, um den Typhinweis anzugeben.

{"x":50,"y":70,"radius":10,"__type":"Circle:#MyApp.Shapes"}

Sowohl die von WCF als auch von ASP.NET AJAX-Clientseiten verwendeten DataContractJsonSerializer geben immer zuerst den Typhinweis aus.

Typenhinweise gelten nur für komplexe Typen

Es gibt keine Möglichkeit, einen Typhinweis für nicht komplexe Typen auszugeben. Wenn ein Vorgang z. B. einen Object Rückgabetyp aufweist, aber einen Circle zurückgibt, kann die JSON-Darstellung wie zuvor dargestellt sein, und die Typinformationen bleiben erhalten. Wenn jedoch Uri zurückgegeben wird, ist die JSON-Darstellung eine Zeichenfolge, und die Tatsache, dass die Zeichenfolge, die zur Darstellung eines Uri verwendet wird, verloren geht. Dies gilt nicht nur für primitive Typen, sondern auch für Sammlungen und Arrays.

Wann Typhinweise ausgegeben werden

Typhinweise können die Nachrichtengröße erheblich erhöhen (eine Möglichkeit, dies zu verringern, besteht darin, kürzere Datenvertragsnamespaces nach Möglichkeit zu verwenden). Daher regeln die folgenden Regeln, ob Typhinweise ausgegeben werden:

  • Bei Verwendung von ASP.NET AJAX werden Typhinweise nach Möglichkeit ausgegeben, auch wenn keine Zuweisung von Basistypen zu abgeleiteten Typen besteht. Dies gilt auch, wenn beispielsweise ein Circle einem Circle zugewiesen ist. (Dies ist erforderlich, um den Prozess des Aufrufens aus der schwach typierten JSON-Umgebung in die stark typierte .NET-Umgebung ohne überraschenden Informationsverlust vollständig zu aktivieren.)

  • Bei Verwendung von AJAX-Diensten ohne ASP.NET-Integration werden Typhinweise nur dann ausgegeben, wenn es eine Zuweisung von Basistypen zu abgeleiteten Typen gibt – also wenn Circle einem Shape-Typ oder einem Object zugewiesen ist, nicht aber, wenn Circle einem Circle zugewiesen ist. Dies stellt die Mindestinformationen bereit, die erforderlich sind, um einen JavaScript-Client korrekt zu implementieren und somit die Leistung zu verbessern, schützt jedoch nicht vor Typinformationsverlusten in falsch entworfenen Clients. Vermeiden Sie grundlegende/abgeleitete Zuordnungen auf dem Server, wenn Sie dieses Problem auf dem Client vermeiden möchten.

  • Wenn Sie den DataContractSerializer Typ verwenden, können Sie mit dem alwaysEmitTypeInformation Konstruktorparameter zwischen den beiden vorherigen Modi auswählen, wobei die Standardeinstellung "false" ist (Typhinweise nur bei Bedarf ausgeben).

Doppelte Datenelementnamen

Abgeleitete Typinformationen sind zusammen mit Basistypinformationen im selben JSON-Objekt vorhanden und können in beliebiger Reihenfolge auftreten. Beispielsweise Shape kann wie folgt dargestellt werden.

{"__type":"Shape:#MyApp.Shapes","x":50,"y":70}

Während Circle wie folgt dargestellt werden kann.

{"__type":"Circle:#MyApp.Shapes","x":50, "radius":10,"y":70}

Wenn der Basistyp Shape auch ein Datenmitglied namens "radius" enthielte, führt dies zu einer Kollision sowohl bei der Serialisierung (da JSON-Objekte keine sich wiederholenden Schlüsselnamen enthalten können) als auch bei der Deserialisierung (da unklar ist, ob "Radius" sich auf Shape.radius oder Circle.radius bezieht). Daher wird das Konzept des "Ausblendens von Eigenschaften" (Datenmitglieder desselben Namens in Basis- und abgeleiteten Klassen) in der Regel nicht in Datenvertrag-Klassen empfohlen; es ist im Falle von JSON tatsächlich verboten.

Polymorphismus und IXmlSerialisierbare Typen

IXmlSerializable-Typen können polymorph einander zugewiesen werden, solange die Anforderungen für bekannte Typen entsprechend den üblichen Datenvertragsregeln eingehalten werden. Die Serialisierung eines IXmlSerializable-Typs anstelle eines Object führt jedoch zu einem Verlust von Typinformationen, da das Ergebnis eine JSON-Zeichenfolge ist.

Polymorphismus und bestimmte Schnittstellentypen

Es ist untersagt, einen Sammlungstyp oder einen Typ zu serialisieren, der IXmlSerializable implementiert, wenn ein Nicht-Sammlungstyp erwartet wird, der nicht IXmlSerializable ist (ausgenommen Object). Beispielsweise eine benutzerdefinierte Schnittstelle IMyInterface und ein Typ MyType, die sowohl IEnumerable<T> vom Typ int als auch IMyInterface implementieren. Es ist unzulässig, MyType aus einem Vorgang zurückzugeben, dessen Rückgabetyp IMyInterface lautet. Dies liegt daran, dass MyType als JSON-Array serialisiert werden muss und einen Typhinweis erfordert. Wie bereits erwähnt, können Sie bei Arrays keinen Typhinweis einfügen, sondern nur bei komplexen Datentypen.

Bekannte Typen und Konfigurationen

Alle von den DataContractSerializer verwendeten bekannten Typmechanismen werden auch auf die gleiche Weise von der DataContractJsonSerializer unterstützt. Beide Serialisierer lesen dasselbe Konfigurationselement, <dataContractSerializer> in <system.runtime.serialization>, um bekannte Typen zu ermitteln, die über eine Konfigurationsdatei hinzugefügt wurden.

Sammlungen, die dem Objekt zugewiesen sind

Sammlungen, die einem Objekt zugewiesen werden, werden serialisiert, als handele es sich um Sammlungen, die IEnumerable<T> implementieren: ein JSON-Array, bei dem jeder Eintrag einen Typhinweis enthält, sofern es sich um einen komplexen Typ handelt. Ein List<T> des Typs Shape, der Object zugewiesen ist, sieht zum Beispiel wie folgt aus:

[{"__type":"Shape:#MyApp.Shapes","x":50,"y":70},
{"__type":"Shape:#MyApp.Shapes","x":58,"y":73},
{"__type":"Shape:#MyApp.Shapes","x":41,"y":32}]

Wenn es wieder in ein Object deserialisiert wird:

  • Shape muss sich in der Liste "Bekannte Typen" befinden. Das Vorhandensein List<T> von Typ Shape in bekannten Typen hat keine Auswirkung. Beachten Sie, dass Sie in diesem Fall Shape bei der Serialisierung nicht in die bekannten Typen aufnehmen müssen, da dies automatisch geschieht.

  • Die Auflistung wird als Array des Typs Object deserialisiert, das Shape-Instanzen enthält.

Abgeleitete Auflistungen, die Basisauflistungen zugewiesen sind

Wenn einer Basisauflistung eine abgeleitete Auflistung zugewiesen wird, wird die Auflistung in der Regel serialisiert, als wäre sie eine Sammlung des Basistyps. Wenn der Elementtyp der abgeleiteten Auflistung jedoch nicht dem Elementtyp der Basisauflistung zugewiesen werden kann, wird eine Ausnahme ausgelöst.

Typhinweise und Wörterbücher

Wenn einem Wörterbuch ein Object zugewiesen ist, wird jeder Key- und Value-Eintrag im Wörterbuch so behandelt, als ob er Object zugewiesen wurde und einen Typ-Hinweis erhält.

Beim Serialisieren von Wörterbuchtypen ist das JSON-Objekt, das die Elemente "Key" und "Value" enthält, von der alwaysEmitTypeInformation Einstellung nicht betroffen und enthält nur einen Typhinweis, wenn für die vorherigen Auflistungsregeln ein Hinweis erforderlich ist.

Gültige JSON-Schlüsselnamen

Der Serialisierer XML-codiert Schlüsselnamen, die keine gültigen XML-Namen sind. Ein Datenelement mit dem Namen "123" hätte beispielsweise einen codierten Namen wie "_x0031__x0032__x0033_", da "123" ein ungültiger XML-Elementname ist (beginnt mit einer Ziffer). Eine ähnliche Situation kann bei einigen internationalen Zeichensätzen auftreten, die in XML-Namen nicht gültig sind. Eine Erläuterung dieser Auswirkung von XML auf die JSON-Verarbeitung finden Sie unter Mapping Between JSON and XML.

Siehe auch