Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
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 vonyellow
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 andereenum
.
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. DasdateTime
-Element stellt die Zeit dar, wann das Ereignis von Interesse aufgetreten ist (es wird erneut zu einemDateTime
in JavaScript, wenn ASP.NET AJAX verwendet wird, und zu einer Zeichenfolge, wenn nicht). Bei der Serialisierung wird dasdateTime
Element immer in GMT serialisiert. Wenn beispielsweise die Uhrzeit 3:00 AM in der Zeitzone von New York beschrieben wird, dann enthältdateTime
die Zeitangabe "8:00 AM" undoffsetMinutes
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 eineenum
zu deserialisieren, wird ohne die korrekten Umwandlungen fehlschlagen, weil eineenum
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 einenum
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 TypShape
in bekannten Typen hat keine Auswirkung. Beachten Sie, dass Sie in diesem FallShape
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.