Udostępnij za pośrednictwem


Autonomiczna serializacja JSON przy użyciu klasy DataContractJsonSerializer

Uwaga / Notatka

Ten artykuł dotyczy DataContractJsonSerializer. W przypadku większości scenariuszy obejmujących serializowanie i deserializacji danych JSON zalecamy interfejsy API w przestrzeni nazw System.Text.Json.

JSON (JavaScript Object Notation) to format danych zaprojektowany specjalnie do użycia przez kod JavaScript działający na stronach internetowych w przeglądarce. Jest to domyślny format danych używany przez usługi ASP.NET AJAX utworzone w programie Windows Communication Foundation (WCF).

Ten format można również użyć podczas tworzenia usług AJAX bez integracji z ASP.NET — w tym przypadku plik XML jest domyślny, ale można wybrać format JSON.

Na koniec, jeśli potrzebujesz wsparcia dla JSON, ale nie tworzysz usługi AJAX, DataContractJsonSerializer umożliwia bezpośrednie serializowanie obiektów .NET do danych JSON i deserializację takich danych z powrotem do instancji typów .NET. Aby uzyskać opis sposobu, w jaki to zrobić, zobacz Instrukcje: serializowanie i deserializowanie danych JSON.

Podczas pracy z JSON obsługiwane są te same typy .NET, z kilkoma wyjątkami, jak te wspierane przez DataContractSerializer. Aby uzyskać listę obsługiwanych typów, zobacz Typy obsługiwane przez serializator kontraktu danych. Obejmuje to większość typów pierwotnych, większość typów tablic i kolekcji, a także typy złożone używające elementów DataContractAttribute i DataMemberAttribute.

Mapuj typy platformy .NET na typy JSON

W poniższej tabeli przedstawiono korespondencję między typami .NET i typami JSON/JavaScript, gdy są mapowane przez procedury serializacji i deserializacji.

Typy .NET JSON/JavaScript Notatki
Wszystkie typy liczbowe, na przykład Int32, Decimal lub Double Liczba Wartości specjalne, takie jak Double.NaN, Double.PositiveInfinity i Double.NegativeInfinity nie są obsługiwane i powodują nieprawidłowy kod JSON.
Enum Liczba Zobacz "Wyliczenia i JSON" w dalszej części tego artykułu.
Boolean boolean
String, Char Sznurek
TimeSpan, , GuidUri Sznurek Format tych typów w formacie JSON jest taki sam jak w formacie XML (zasadniczo przedział czasu w formacie trwania ISO 8601, identyfikator GUID w formacie "12345678-ABCD-ABCD-ABCD-1234567890AB" i identyfikator URI w postaci ciągu naturalnego, na przykład "http://www.example.com"). Aby uzyskać dokładne informacje, zobacz Data Contract Schema Reference (Dokumentacja schematu kontraktu danych).
XmlQualifiedName Sznurek Format to: "name:namespace" (wszystko przed pierwszym dwukropkiem to nazwa). Nazwa lub przestrzeń nazw może być brakująca. Jeśli nie ma przestrzeni nazw, dwukropek można również pominąć.
Array typu Byte Tablica liczb Każda liczba reprezentuje wartość jednego bajtu.
DateTime Data/godzina lub ciąg Zobacz daty/godziny i dane JSON w dalszej części tego artykułu.
DateTimeOffset Typ złożony Zobacz daty/godziny i dane JSON w dalszej części tego artykułu.
Typy XML i ADO.NET (XmlElement,

XElement. Tablice z wartościami XmlNode,

ISerializable,

DataSet).
Sznurek Zobacz sekcję Typy XML i kod JSON w tym artykule.
DBNull Pusty typ złożony --
Kolekcje, słowniki i tablice Tablica Zobacz sekcję Kolekcje, Słowniki i Tablice tego tematu.
Typy złożone (z DataContractAttribute lub SerializableAttribute zastosowanymi) Typ złożony Składowe danych stają się członkami typu złożonego języka JavaScript.
Złożone typy implementowania interfejsu ISerializable ) Typ złożony Niektóre typy ISerializable nie są obsługiwane, podobnie jak w przypadku innych złożonych typów — zobacz Obsługę ISerializable.
Null wartość dla dowolnego typu Zero Typy wartości dopuszczające wartości nullowe są również obsługiwane i mapowane na format JSON w taki sam sposób, jak typy wartości nie-dopuszczające wartości null.

Wyliczenia i JSON

Wartości składowych wyliczenia są traktowane jako liczby w formacie JSON, co różni się od sposobu traktowania ich w kontraktach danych, gdzie są uwzględniane jako nazwy elementów członkowskich. Aby uzyskać więcej informacji na temat obsługi kontraktów danych, zobacz Typy wyliczenia w kontraktach danych.

  • Na przykład, jeśli masz public enum Color {red, green, blue, yellow, pink}, serializowanie yellow generuje liczbę 3, a nie ciąg "żółty".

  • Wszystkich enum członków można serializować. Atrybuty EnumMemberAttribute i NonSerializedAttribute są ignorowane, jeśli są używane.

  • Istnieje możliwość deserializacji nieistniejącej wartości enum — na przykład wartość 87 można deserializować do wcześniejszego wyliczenia Color, mimo że nie zdefiniowano odpowiedniej nazwy koloru.

  • Flagi enum nie są specjalne i są traktowane tak samo jak inne enum.

Daty/godziny i dane JSON

Format JSON nie obsługuje bezpośrednio dat i godzin. Są one jednak bardzo często używane i ASP.NET AJAX zapewnia specjalną obsługę tych typów. W przypadku korzystania z proxy ASP.NET AJAX, typ DateTime w .NET w pełni odpowiada typowi DateTime w języku JavaScript.

  • Jeśli nie używasz ASP.NET, typ DateTime jest reprezentowany w języku JSON jako ciąg znaków w specjalnym formacie opisanym w sekcji Informacje zaawansowane w tym temacie.

  • DateTimeOffset element jest reprezentowany w formacie JSON jako typ złożony: {"DateTime":d ateTime,"OffsetMinutes":offsetMinutes}. Członek offsetMinutes jest przesunięciem czasu lokalnego względem Greenwich Mean Time (GMT), który obecnie nazywany jest także uniwersalnym czasem koordynowanym (UTC), związanym z miejscem interesującego zdarzenia. Element członkowski dateTime reprezentuje punkt w czasie, kiedy wystąpiło interesujące zdarzenie (ponownie staje się DateTime w języku JavaScript, gdy ASP.NET AJAX jest używany, oraz ciągiem, gdy nie jest). Podczas serializacji członek dateTime jest zawsze serializowany w GMT. Tak więc, jeśli mówimy o czasie 3:00 rano czasu nowojorskiego, dateTime odpowiada godzinie 8:00, a offsetMinutes to przesunięcie o 300 minut (minus 300 minut lub 5 godzin od GMT).

    Uwaga / Notatka

    DateTime i DateTimeOffset obiekty, w przypadku serializacji do formatu JSON, zachowują tylko informacje o dokładności milisekundowej. Wartości pod milisekund (mikro/nanosekundy) są tracone podczas serializacji.

Typy XML i dane JSON

Typy XML stają się ciągami JSON.

  • Jeśli na przykład element członkowski danych "q" typu XElement zawiera <abc/>, kod JSON to {"q":"<abc/>"}.

  • Istnieją pewne specjalne reguły, które określają sposób opakowania kodu XML — aby uzyskać więcej informacji, zobacz sekcję Informacje zaawansowane w dalszej części tego artykułu.

  • Jeśli używasz ASP.NET AJAX i nie chcesz używać ciągów w JavaScript, ale zamiast tego chcesz używać DOM XML, ustaw właściwość ResponseFormat na XML w WebGetAttribute lub właściwość ResponseFormat na XML w WebInvokeAttribute.

Kolekcje, słowniki i tablice

Wszystkie kolekcje, słowniki i tablice są reprezentowane w formacie JSON jako tablice.

  • Każde dostosowanie, które używa elementu CollectionDataContractAttribute , jest ignorowane w reprezentacji JSON.

  • Słowniki nie są sposobem pracy bezpośrednio z plikiem JSON. Dictionary<string,object> może nie być obsługiwany w taki sam sposób w programie WCF, jak oczekiwano podczas pracy z innymi technologiami JSON. Jeśli na przykład "abc" jest mapowany na "xyz", a wyrażenie "def" jest mapowane na 42 w słowniku, reprezentacja JSON nie jest {"abc":"xyz","def":42}, ale to [{"Key":"abc","Value":"xyz"},{"Key":"def","Value":42}].

  • Jeśli chcesz pracować bezpośrednio z plikiem JSON (dynamiczne uzyskiwanie dostępu do kluczy i wartości bez wstępnego definiowania sztywnego kontraktu), masz kilka opcji:

    • Rozważ użycie przykładu serializacji JSON o słabej typizacji (AJAX).

    • Rozważ użycie interfejsu ISerializable oraz konstruktorów deserializacji – te dwa mechanizmy umożliwiają dostęp do par klucz/wartość JSON podczas serializacji i deserializacji, ale nie działają w sytuacjach z częściowym zaufaniem.

    • Rozważ korzystanie z mapowania między formatami JSON i XML zamiast z serializatora.

    • Polimorfizm w kontekście serializacji odnosi się do możliwości serializacji typu pochodnego w sytuacji, gdy oczekiwany jest typ podstawowy. Istnieją specjalne reguły specyficzne dla formatu JSON podczas używania kolekcji polimorficznie, na przykład podczas przypisywania kolekcji do klasy Object. Ten problem jest bardziej szczegółowo omówiony w sekcji Informacje zaawansowane w dalszej części tego artykułu.

Dodatkowe szczegóły

Kolejność członków danych

Kolejność elementów członkowskich danych nie jest ważna w przypadku korzystania z formatu JSON. W szczególności, nawet jeśli Order jest ustawiona, dane JSON nadal mogą być deserializowane w dowolnej kolejności.

Typy JSON

Typ JSON nie musi być zgodny z poprzednią tabelą w przypadku deserializacji. Na przykład Int zwykle mapuje się na liczbę JSON, ale można ją również pomyślnie zdeserializować z ciągu JSON, o ile ten ciąg zawiera prawidłową liczbę. Oznacza to, że zarówno {"q":42} jak i {"q":"42"} są prawidłowe, jeśli istnieje Int element członkowski danych o nazwie "q".

Polimorfizm

Serializacja polimorficzna polega na możliwości serializacji typu pochodnego w sytuacji, gdy oczekiwany jest typ podstawowy. Obsługiwane jest to dla serializacji JSON przez WCF w sposób porównywalny do obsługi serializacji XML. Na przykład można serializować MyDerivedType , gdzie MyBaseType jest oczekiwana, lub serializować Int , gdzie Object jest oczekiwana.

Informacje o typie mogą zostać utracone podczas deserializacji typu pochodnego, jeśli typ podstawowy jest oczekiwany, chyba że deserializuje się typ złożony. Na przykład, jeśli Uri zostanie zserializowany w miejscu, gdzie oczekiwany jest Object, powstanie ciąg JSON. Jeśli ten ciąg zostanie następnie zdeserializowany z powrotem do Object, zwracany jest String .NET. Deserializator nie wie, że ciąg był początkowo typem Uri. Ogólnie rzecz biorąc, podczas oczekiwania na Object wszystkie ciągi JSON są deserializowane jako ciągi .NET, a wszystkie tablice JSON używane do serializacji kolekcji .NET, słowników i tablic są deserializowane jako .NET Array typu Object, niezależnie od rzeczywistego oryginalnego typu. Wartość logiczna JSON mapuje na platformę .NET Boolean. Jednak gdy oczekuje się Object, liczby JSON są deserializowane jako .NET Int32, Decimal lub Double, gdzie najbardziej odpowiedni typ jest wybierany automatycznie.

Podczas deserializacji do typu interfejsu, DataContractJsonSerializer jest deserializowane tak, jakby zadeklarowanym typem był obiekt.

Podczas pracy z własnymi typami bazowymi i pochodnymi zwykle wymagane jest użycie KnownTypeAttribute, ServiceKnownTypeAttribute lub równorzędnego mechanizmu. Jeśli na przykład masz operację, która ma wartość zwracaną Animal i w rzeczywistości zwraca wystąpienie Cat (pochodzące z Animal), należy zastosować parametr KnownTypeAttribute do typu Animal lub ServiceKnownTypeAttribute do operacji i określić typ Cat w tych atrybutach. Aby uzyskać więcej informacji, zobacz Znane typy kontraktów danych.

Aby uzyskać szczegółowe informacje na temat działania serializacji polimorficznej oraz omówienie niektórych ograniczeń, które należy przestrzegać podczas korzystania z niej, zobacz sekcję Informacje zaawansowane w dalszej części tego artykułu.

Wersjonowanie

Funkcje wersjonowania kontraktu danych, w tym interfejs IExtensibleDataObject, są w pełni obsługiwane w formacie JSON. Ponadto w większości przypadków można deserializować typ w jednym formacie (na przykład XML), a następnie serializować go w innym formacie (na przykład w formacie JSON) i zachować dane w IExtensibleDataObjectpliku . Aby uzyskać więcej informacji, zobacz Forward-Compatible Kontrakty danych. Pamiętaj, że kod JSON jest nieurządkowany, więc wszystkie informacje o zamówieniu zostaną utracone. Ponadto kod JSON nie obsługuje wielu par klucz/wartość o tej samej nazwie klucza. Na koniec wszystkie operacje na IExtensibleDataObject są z natury polimorficzne — to ich typy pochodne są przypisywane do Object, typu bazowego dla wszystkich typów.

Kod JSON w adresach URL

W przypadku używania ASP.NET punktów końcowych AJAX z czasownikiem HTTP GET (przy użyciu atrybutu WebGetAttribute ) parametry przychodzące są wyświetlane w adresie URL żądania zamiast treści komunikatu. Kod JSON jest obsługiwany nawet w adresie URL żądania, więc jeśli masz operację, która przyjmuje Int nazwę "number" i Person typ złożony o nazwie "p", adres URL może przypominać następujący adres URL.

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

Jeśli używasz kontrolki menedżera skryptów AJAX ASP.NET i serwera proxy do wywoływania usługi, ten adres URL jest generowany automatycznie przez serwer proxy i nie jest widoczny. Nie można używać kodu JSON w adresach URL w punktach końcowych AJAX non-ASP.NET.

Zaawansowane informacje

Obsługa interfejsu ISerializable

Obsługiwane i nieobsługiwane typy ISerializable

Ogólnie rzecz biorąc, typy implementujące ISerializable interfejs są w pełni obsługiwane podczas serializacji/deserializacji JSON. Jednak niektóre z tych typów (w tym niektóre typy .NET Framework) są implementowane w taki sposób, że aspekty serializacji specyficzne dla formatu JSON powodują, że nie są one poprawnie deserializowane.

  • W programie ISerializabletyp poszczególnych składowych danych nigdy nie jest znany z wyprzedzeniem. Prowadzi to do sytuacji polimorficznej podobnej do deserializacji typów do obiektu. Jak wspomniano wcześniej, może to prowadzić do utraty informacji o typie w formacie JSON. Na przykład, typ, który serializuje enum w swojej implementacji ISerializable i próbuje deserializować bezpośrednio do enum (bez odpowiednich rzutów), kończy się niepowodzeniem, ponieważ enum jest serializowane przy użyciu liczb JSON, a liczby JSON deserializują się we wbudowane typy liczbowe .NET (Int32, Decimal lub Double). Fakt, że liczba była wcześniej wartością enum, zostaje utracony.

  • Typ ISerializable , który zależy od określonej kolejności deserializacji w konstruktorze deserializacji, może również nie wykonać deserializacji niektórych danych JSON, ponieważ większość serializatorów JSON nie gwarantuje żadnej określonej kolejności.

Typy fabryk

Chociaż interfejs IObjectReference jest ogólnie obsługiwany w formacie JSON, wszelkie typy wymagające funkcji "typu fabryki" (zwracanie wystąpienia innego typu niż typ GetRealObject(StreamingContext) implementujący interfejs) nie są obsługiwane.

Format przewodu daty/godziny

DateTime wartości pojawiają się jako ciągi JSON w postaci "/Date(700000+0500)/", gdzie pierwsza liczba (700000 w podanym przykładzie) jest liczbą milisekund w strefie czasowej GMT, czas standardowy (nieczas letni) od północy 1 stycznia 1970 roku. Liczba może być ujemna, aby reprezentować wcześniejsze czasy. Część zawierająca "+0500" w przykładzie jest opcjonalna i wskazuje, że czas jest rodzaju Local, co oznacza, że podczas deserializacji powinien zostać przekonwertowany na lokalną strefę czasową. Jeśli jest nieobecny, czas jest deserializowany jako Utc. Rzeczywista liczba ("0500" w tym przykładzie) i jej znak (+ lub -) są ignorowane.

Podczas serializacji czasy DateTime, Local i Unspecified są zapisywane z przesunięciem, a Utc jest zapisywany bez przesunięcia.

Kod JavaScript klienta ASP.NET AJAX automatycznie konwertuje takie ciągi na wystąpienia języka JavaScript DateTime . Jeśli istnieją inne ciągi, które mają podobną formę, nie będące typu DateTime na platformie .NET, są również konwertowane.

Konwersja odbywa się tylko wtedy, gdy znaki "/" zostaną uniknięci (tj. kod JSON wygląda następująco: "\/Date(70000+0500)\/"), a z tego powodu koder JSON programu WCF (włączony przez WebHttpBinding) zawsze unika znaku "/".

Kod XML w ciągach JSON

Element Xml

XmlElement jest serializowany w stanie niezmienionym, bez zawijania. Na przykład element członkowski danych "x" typu XmlElement zawierający <abc/> jest reprezentowany w następujący sposób:

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

Tablice XmlNode

Array obiekty typu XmlNode są opakowane w element o nazwie ArrayOfXmlNode w standardowej przestrzeni nazw kontraktu danych dla typu. Jeśli "x" jest tablicą zawierającą węzeł atrybutu "N" w przestrzeni nazw "ns", która zawiera "value" i pusty węzeł elementu "M", reprezentacja jest następująca.

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

Atrybuty w pustej przestrzeni nazw na początku tablic XmlNode (przed innymi elementami) nie są obsługiwane.

Typy interfejsu IXmlSerializable, w tym XElement i DataSet

ISerializable typy dzielą się na "typy zawartości", "Typy zestawów danych" i "typy elementów". Definicje tych typów można znaleźć w temacie XML i ADO.NET Types in Data Contracts (Typy XML i ADO.NET w kontraktach danych).

Typy "Content" i "DataSet" są serializowane w taki sposób, jak Array obiekty XmlNode omówione w poprzedniej sekcji. Są one opakowane w element, którego nazwa i przestrzeń nazw odpowiadają nazwie kontraktu danych i przestrzeni nazw danego typu.

Typy „Element”, takie jak XElement, są serializowane tak samo, jak XmlElement, które zostały wcześniej omówione w tym artykule.

Polimorfizm

Zachowywanie informacji o typie

Jak wspomniano wcześniej, polimorfizm jest obsługiwany w formacie JSON z pewnymi ograniczeniami. Język JavaScript jest językiem słabo typowanym, a tożsamość typu zazwyczaj nie stanowi problemu. Jednak w przypadku używania formatu JSON do komunikacji między silnie typizowanym systemem (.NET) a słabo typizowanym systemem (JavaScript), warto zachować tożsamość typu. Na przykład typy o nazwach kontraktów danych "Square" i "Circle" pochodzą z typu o nazwie kontraktu danych "Kształt". Jeśli obiekt "Circle" jest wysyłany z platformy .NET do języka JavaScript, a później zwracany do metody .NET, która oczekuje "Shape", ważne jest, aby strona .NET wiedziała, że obiekt był pierwotnie "Circle" — w przeciwnym razie wszelkie informacje specyficzne dla typu pochodnego (na przykład członek danych "radius" w "Circle") mogą zostać utracone.

Aby zachować tożsamość typu, podczas serializacji typów złożonych w formacie JSON można dodać "wskazówkę typu", a deserializator rozpoznaje wskazówkę i działa odpowiednio. "Wskazówka dotycząca typu" jest parą klucz/wartość JSON z kluczem o nazwie "__type" (dwa podkreślenia, a następnie słowo "type"). Wartość jest ciągiem JSON w formacie "DataContractName:DataContractNamespace", gdzie wszystko przed pierwszym dwukropkiem jest nazwą. Korzystając z wcześniejszego przykładu, "Circle" można serializować w następujący sposób.

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

Wskazówka typu jest bardzo podobna do atrybutu xsi:type zdefiniowanego przez standard wystąpienia schematu XML i używanego podczas serializacji/deserializacji XML.

Członkowie danych o nazwie "__type" są zabronieni ze względu na potencjalny konflikt z podpowiedzią typu.

Zmniejszenie rozmiaru wskazówek typu

Aby zmniejszyć rozmiar komunikatów JSON, domyślny prefiks przestrzeni nazw kontraktu danych (http://schemas.datacontract.org/2004/07/) jest zastępowany znakiem "#". (Aby to zastąpienie było odwracalne, stosowana jest reguła ucieczki: jeśli przestrzeń nazw zaczyna się od znaków "#" lub "\", do tych znaków dodawany jest dodatkowy znak "\"). W związku z tym, jeśli "Circle" jest typem w przestrzeni nazw .NET "MyApp.Shapes", domyślną przestrzenią nazw kontraktu danych jest http://schemas.datacontract.org/2004/07/MyApp. Kształty i reprezentacja JSON są następujące.

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

Zarówno skrócone (#MyApp.Kształty), jak i pełne (http://schemas.datacontract.org/2004/07/MyApp.Shapes) nazwy są rozpoznawane podczas procesu deserializacji.

Pozycja wskazówki typu w obiektach JSON

Należy pamiętać, że wskazówka typu musi pojawić się najpierw w reprezentacji JSON. Jest to jedyny przypadek, w którym kolejność par klucz/wartość jest ważna w przetwarzaniu JSON. Na przykład następujące informacje nie są prawidłowym sposobem określenia wskazówki dotyczącej typu.

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

DataContractJsonSerializer Zarówno używane przez program WCF, jak i ASP.NET strony klienta AJAX zawsze emitują najpierw wskazówkę dotyczącą typu.

Wskazówki dotyczące typów mają zastosowanie tylko do typów złożonych

Nie ma możliwości podania wskazówki typu dla typów nieskomplikowanych. Jeśli na przykład operacja ma typ zwracany Object , ale zwraca okrąg, reprezentacja JSON może być jak pokazano wcześniej, a informacje o typie są zachowywane. Jeśli jednak zostanie zwrócony identyfikator URI, reprezentacja JSON jest ciągiem, a fakt, że był on używany do reprezentowania identyfikatora URI, zostaje utracony. Dotyczy to nie tylko typów pierwotnych, ale także kolekcji i tablic.

Kiedy są generowane wskazówki dotyczące typu

Wskazówki dotyczące typów mogą znacznie zwiększyć rozmiar komunikatu (jednym ze sposobów ograniczenia tego problemu jest użycie krótszych przestrzeni nazw kontraktu danych, jeśli jest to możliwe). W związku z tym następujące reguły określają, czy są emitowane wskazówki dotyczące typu:

  • W przypadku używania ASP.NET AJAX wskazówki dotyczące typów są zawsze emitowane zawsze, jeśli jest to możliwe, nawet jeśli nie ma przypisania podstawowego/pochodnego — na przykład, nawet jeśli koło jest przypisane do okręgu. (Jest to wymagane, aby w pełni umożliwić proces wywoływania ze słabo typizowanego środowiska JSON do silnie typizowanego środowiska .NET bez zaskakującej utraty informacji).

  • W przypadku korzystania z usług AJAX bez integracji z ASP.NET, wskazówki dotyczące typów są emitowane tylko wtedy, gdy istnieje przypisanie podstawowe/pochodne — czyli emitowane, gdy Circle jest przypisany do Shape lub Object, ale nie w przypadku przypisania do Circle. Zapewnia to minimalne informacje wymagane do poprawnego zaimplementowania klienta JavaScript, co zwiększa wydajność, ale nie chroni przed utratą informacji o typie niepoprawnie zaprojektowanych klientów. Unikaj przypisań bazowych/pochodnych w całości na serwerze, jeśli chcesz uniknąć radzenia sobie z tym problemem na kliencie.

  • W przypadku użycia typu DataContractSerializer, parametr konstruktora alwaysEmitTypeInformation umożliwia wybór między dwoma wcześniejszymi trybami, z wartością domyślną "false" (emituj podpowiedzi typu tylko wtedy, gdy jest to wymagane).

Zduplikowane nazwy członów danych

Informacje o typie pochodnym znajdują się w tym samym obiekcie JSON wraz z informacjami o typie podstawowym i mogą występować w dowolnej kolejności. Na przykład Shape może być reprezentowana w następujący sposób.

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

Koło można przedstawić w następujący sposób.

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

Jeśli typ bazowy Shape zawiera również członka danych o nazwie "radius", doprowadza to do kolizji podczas serializacji (ponieważ obiekty JSON nie mogą mieć powtarzających się nazw kluczy) i deserializacji (ponieważ nie jest jasne, czy "promień" odnosi się do Shape.radius czy Circle.radius). W związku z tym pojęcie "ukrywanie właściwości" (członkowie danych o tej samej nazwie w klasach bazowych i pochodnych) zazwyczaj nie jest zalecane w klasach kontraktów danych, a w przypadku formatu JSON jest wręcz zabronione.

Polimorfizm i typy interfejsu IXmlSerializable

IXmlSerializable typy mogą być przypisywane polimorficznie względem siebie, tak jak zwykle, o ile są spełnione wymagania dotyczące Znanych Typów, zgodnie z zwykłymi regułami kontraktu danych. Jednak serializowanie IXmlSerializable typu w miejsce Object, powoduje utratę informacji o typie, w wyniku czego otrzymujemy ciąg JSON.

Polimorfizm i niektóre typy interfejsów

Zabronione jest serializowanie typu kolekcji lub typu, który implementuje IXmlSerializable, gdy oczekiwany jest typ inny niż kolekcja, który nie jest IXmlSerializable (z wyjątkiem Object). Na przykład interfejs niestandardowy o nazwie IMyInterface oraz typ MyType, które implementują zarówno IEnumerable<T> typu int, jak i IMyInterface. Nie można wrócić MyType z operacji, której zwracany typ to IMyInterface. Jest to spowodowane tym, że MyType musi być serializowana jako tablica JSON i wymaga wskazówki o typie, a jak określono wcześniej, nie można dołączyć wskazówki typu z tablicami, tylko w przypadku typów złożonych.

Znane typy i konfiguracja

Wszystkie znane mechanizmy typu używane przez DataContractSerializer są również obsługiwane w ten sam sposób przez DataContractJsonSerializer. Oba serializatory odczytują ten sam element konfiguracji, <dataContractSerializer> w <pliku system.runtime.serialization>, aby odnaleźć znane typy dodane za pośrednictwem pliku konfiguracji.

Kolekcje przypisane do obiektu

Kolekcje przypisane do obiektu są serializowane tak, jakby były kolekcjami implementowanymi IEnumerable<T>: tablicą JSON z każdym wpisem zawierającym wskazówkę typu, jeśli jest to typ złożony. Na przykład List<T>, typ Shape, przypisany do Object wygląda następująco.

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

Podczas deserializacji z powrotem do Object:

  • Shape musi znajdować się na liście Znane typy. Posiadanie List<T> typu Shape w znanych typach nie ma wpływu. Należy pamiętać, że nie trzeba dodawać Shape do znanych typów serializacji w tym przypadku — odbywa się to automatycznie.

  • Kolekcja jest deserializowana jako Array typu Object, który zawiera Shape wystąpienia.

Kolekcje pochodne przypisane do kolekcji bazowych

Gdy kolekcja pochodna jest przypisywana do kolekcji podstawowej, kolekcja jest zwykle serializowana tak, jakby była kolekcją typu podstawowego. Jeśli jednak nie można przypisać typu elementu kolekcji pochodnej do typu elementu kolekcji podstawowej, zgłaszany jest wyjątek.

Wskazówki dotyczące typów i słowniki

Po przypisaniu słownika do elementu Object, każdy wpis Klucza i Wartości w słowniku jest traktowany tak, jakby został przypisany do Object i otrzymuje wskazówkę typu.

Podczas serializacji typów słowników obiekt JSON zawierający elementy członkowskie "Klucz" i "Wartość" nie ma wpływu na ustawienia alwaysEmitTypeInformation i zawiera tylko wskazówkę typu, gdy wcześniejsze reguły kolekcji tego wymagają.

Prawidłowe nazwy kluczy JSON

Serializator XML koduje nazwy kluczy, które nie są prawidłowymi nazwami XML. Na przykład element członkowski danych o nazwie "123" będzie miał zakodowaną nazwę, taką jak "_x0031__x0032__x0033_", ponieważ "123" jest nieprawidłową nazwą elementu XML (zaczyna się od cyfry). Podobna sytuacja może wystąpić w przypadku niektórych międzynarodowych zestawów znaków nieprawidłowych w nazwach XML. Aby uzyskać wyjaśnienie tego wpływu kodu XML na przetwarzanie JSON, zobacz Mapowanie między formatami JSON i XML.

Zobacz także