Migrowanie z Newtonsoft.Json do System.Text.Json

W tym artykule pokazano, jak przeprowadzić migrację z Newtonsoft.Json programu do System.Text.Jsonprogramu .

System.Text.Json Przestrzeń nazw zapewnia funkcje serializacji do i deserializacji z pliku JavaScript Object Notation (JSON). Biblioteka jest zawarta System.Text.Json w środowisku uruchomieniowym platformy .NET Core 3.1 i nowszych wersjach. W przypadku innych platform docelowych zainstaluj System.Text.Json pakiet NuGet. Pakiet obsługuje:

  • .NET Standard 2.0 i nowsze wersje
  • .NET Framework 4.7.2 i nowsze wersje
  • .NET Core 2.0, 2.1 i 2.2

System.Text.Json koncentruje się głównie na wydajności, bezpieczeństwie i zgodności ze standardami. Ma ona pewne kluczowe różnice w zachowaniu domyślnym i nie ma na celu parzystości funkcji z Newtonsoft.Json. W przypadku niektórych scenariuszy System.Text.Json obecnie nie ma wbudowanych funkcji, ale istnieją zalecane obejścia. W przypadku innych scenariuszy obejścia są niepraktyczne.

Inwestujemy w dodawanie funkcji, które są najczęściej wymagane. Jeśli aplikacja zależy od brakującej funkcji, rozważ zgłoszenie problemu w repozytorium dotnet/runtime GitHub, aby dowiedzieć się, czy można dodać obsługę danego scenariusza.

Większość tego artykułu dotyczy sposobu korzystania z interfejsu JsonSerializer API, ale zawiera również wskazówki dotyczące używania JsonDocument (który reprezentuje model obiektów dokumentów lub DOM), Utf8JsonReaderi Utf8JsonWriter typów.

W języku Visual Basic nie można użyć Utf8JsonReaderelementu , co oznacza również, że nie można pisać konwerterów niestandardowych. Większość przedstawionych tutaj obejść wymaga pisania konwerterów niestandardowych. Konwerter niestandardowy można napisać w języku C# i zarejestrować go w projekcie Języka Visual Basic. Aby uzyskać więcej informacji, zobacz Obsługa języka Visual Basic.

Tabela różnic

W poniższej tabeli wymieniono Newtonsoft.Json funkcje i System.Text.Json odpowiedniki. Odpowiedniki należą do następujących kategorii:

  • ✔️ Obsługiwane przez wbudowane funkcje. Uzyskanie podobnego zachowania System.Text.Json może wymagać użycia atrybutu lub opcji globalnej.
  • ⚠✔ Nieobsługiwane, ale możliwe jest obejście problemu. Obejścia to konwertery niestandardowe, które mogą nie zapewniać pełnej równoważności z funkcjami Newtonsoft.Json . W przypadku niektórych z nich przykładowy kod jest dostarczany jako przykłady. Jeśli korzystasz z tych Newtonsoft.Json funkcji, migracja będzie wymagać modyfikacji modeli obiektów platformy .NET lub innych zmian kodu.
  • ❌ Nieobsługiwane, a obejście nie jest praktyczne ani możliwe. Jeśli korzystasz z tych Newtonsoft.Json funkcji, migracja nie będzie możliwa bez istotnych zmian.
Funkcja systemu Newtonsoft.Json System.Text.Json Równoważne
Deserializacji bez uwzględniania wielkości liter domyślnie ✔️ Ustawienie globalne WłaściwościNameCaseInsensitive
Nazwy właściwości camel-case ✔️ Ustawienie globalne PropertyNamingPolicy
Nazwy właściwości Snake-case ✔️ Zasady nazewnictwa przypadków węża
Minimalny znak ucieczki ✔️ Ścisłe znaki ucieczki, konfigurowalne
NullValueHandling.Ignore ustawienie globalne ✔️ Opcja globalna DefaultIgnoreCondition
Zezwalaj na komentarze ✔️ ReadCommentHandling — ustawienie globalne
Zezwalaj na przecinki końcowe ✔️ Ustawienie globalne AllowTrailingCommas
Rejestracja konwertera niestandardowego ✔️ Kolejność pierwszeństwa różni się
Domyślna maksymalna głębokość 64, konfigurowalna ✔️ Domyślna maksymalna głębokość 64, konfigurowalna
PreserveReferencesHandling ustawienie globalne ✔️ Ustawienie globalne ReferenceHandling
Serializowanie lub deserializowanie liczb w cudzysłowie ✔️ NumberHandling ustawienia globalnego [JsonNumberHandling] atrybut
Deserializowanie do niezmiennych klas i struktur ✔️ JsonConstructor, rekordy języka C# 9
Obsługa pól ✔️ Ustawienie globalne IncludeFields, atrybut [JsonInclude]
DefaultValueHandling ustawienie globalne ✔️ Ustawienie globalne DefaultIgnoreCondition
NullValueHandling ustawienie włączone [JsonProperty] ✔️ Atrybut JsonIgnore
DefaultValueHandling ustawienie włączone [JsonProperty] ✔️ Atrybut JsonIgnore
Deserializowanie Dictionary przy użyciu klucza innego niż ciąg ✔️ Obsługiwane
Obsługa zestawów właściwości innych niż publiczne i metody pobierania ✔️ Atrybut JsonInclude
Atrybut [JsonConstructor] ✔️ [JsonConstructor] , atrybut
ReferenceLoopHandling ustawienie globalne ✔️ Ustawienie globalne ReferenceHandling
Wywołania zwrotne ✔️ Wywołania zwrotne
NaN, Infinity, -Infinity ✔️ Obsługiwane
Requiredustawienie atrybutu [JsonProperty] ✔️ [JsonRequired] atrybut i wymagany modyfikator języka C#
DefaultContractResolver aby zignorować właściwości ✔️ DefaultJsonTypeInfoResolver, klasa
Serializacja polimorficzna ✔️ [JsonDerivedType] , atrybut
Deserializacja polimorficzna ✔️ Dyskryminujący typ atrybutu [JsonDerivedType]
Deserializowanie wartości wyliczenia ciągów ✔️ Deserializowanie wartości wyliczenia ciągów
MissingMemberHandling ustawienie globalne ✔️ Obsługa brakujących elementów członkowskich
Wypełnianie właściwości bez ustawiających ✔️ Wypełnianie właściwości bez ustawiających
ObjectCreationHandling ustawienie globalne ✔️ Ponowne użycie, a nie zastępowanie właściwości
Obsługa szerokiego zakresu typów ⚠✔ Niektóre typy wymagają konwerterów niestandardowych
Deserializowanie wnioskowania typu do object właściwości ⚠✔ Nieobsługiwane, obejście, przykład
Deserializowanie literału JSON null do typów wartości innych niż null ⚠✔ Nieobsługiwane, obejście, przykład
DateTimeZoneHandling, DateFormatString ustawienia ⚠✔ Nieobsługiwane, obejście, przykład
JsonConvert.PopulateObject Metoda ⚠✔ Nieobsługiwane, obejście
Obsługa System.Runtime.Serialization atrybutów ⚠✔ Nieobsługiwane, obejście, przykład
JsonObjectAttribute ⚠✔ Nieobsługiwane, obejście
Zezwalaj na nazwy właściwości bez cudzysłowów Nieobsługiwane przez projekt
Zezwalaj na pojedyncze cudzysłowy wokół wartości ciągu Nieobsługiwane przez projekt
Zezwalaj na wartości JSON innych niż ciąg dla właściwości ciągu Nieobsługiwane przez projekt
TypeNameHandling.All ustawienie globalne Nieobsługiwane przez projekt
Obsługa JsonPath zapytań Nieobsługiwane
Konfigurowalne limity Nieobsługiwane
Funkcja systemu Newtonsoft.Json System.Text.Json Równoważne
Deserializacji bez uwzględniania wielkości liter domyślnie ✔️ Ustawienie globalne WłaściwościNameCaseInsensitive
Nazwy właściwości camel-case ✔️ Ustawienie globalne PropertyNamingPolicy
Minimalny znak ucieczki ✔️ Ścisłe znaki ucieczki, konfigurowalne
NullValueHandling.Ignore ustawienie globalne ✔️ Opcja globalna DefaultIgnoreCondition
Zezwalaj na komentarze ✔️ ReadCommentHandling — ustawienie globalne
Zezwalaj na przecinki końcowe ✔️ Ustawienie globalne AllowTrailingCommas
Rejestracja konwertera niestandardowego ✔️ Kolejność pierwszeństwa różni się
Domyślna maksymalna głębokość 64, konfigurowalna ✔️ Domyślna maksymalna głębokość 64, konfigurowalna
PreserveReferencesHandling ustawienie globalne ✔️ Ustawienie globalne ReferenceHandling
Serializowanie lub deserializowanie liczb w cudzysłowie ✔️ NumberHandling ustawienia globalnego [JsonNumberHandling] atrybut
Deserializowanie do niezmiennych klas i struktur ✔️ JsonConstructor, rekordy języka C# 9
Obsługa pól ✔️ Ustawienie globalne IncludeFields, atrybut [JsonInclude]
DefaultValueHandling ustawienie globalne ✔️ Ustawienie globalne DefaultIgnoreCondition
NullValueHandling ustawienie włączone [JsonProperty] ✔️ Atrybut JsonIgnore
DefaultValueHandling ustawienie włączone [JsonProperty] ✔️ Atrybut JsonIgnore
Deserializowanie Dictionary przy użyciu klucza innego niż ciąg ✔️ Obsługiwane
Obsługa zestawów właściwości innych niż publiczne i metody pobierania ✔️ Atrybut JsonInclude
Atrybut [JsonConstructor] ✔️ [JsonConstructor] , atrybut
ReferenceLoopHandling ustawienie globalne ✔️ Ustawienie globalne ReferenceHandling
Wywołania zwrotne ✔️ Wywołania zwrotne
NaN, Infinity, -Infinity ✔️ Obsługiwane
Requiredustawienie atrybutu [JsonProperty] ✔️ [JsonRequired] atrybut i wymagany modyfikator języka C#
DefaultContractResolver aby zignorować właściwości ✔️ DefaultJsonTypeInfoResolver, klasa
Serializacja polimorficzna ✔️ [JsonDerivedType] , atrybut
Deserializacja polimorficzna ✔️ Dyskryminujący typ atrybutu [JsonDerivedType]
Deserializowanie wartości wyliczenia ciągów ✔️ Deserializowanie wartości wyliczenia ciągów
Obsługa szerokiego zakresu typów ⚠✔ Niektóre typy wymagają konwerterów niestandardowych
Deserializowanie wnioskowania typu do object właściwości ⚠✔ Nieobsługiwane, obejście, przykład
Deserializowanie literału JSON null do typów wartości innych niż null ⚠✔ Nieobsługiwane, obejście, przykład
DateTimeZoneHandling, DateFormatString ustawienia ⚠✔ Nieobsługiwane, obejście, przykład
JsonConvert.PopulateObject Metoda ⚠✔ Nieobsługiwane, obejście
ObjectCreationHandling ustawienie globalne ⚠✔ Nieobsługiwane, obejście
Dodawanie do kolekcji bez elementów ustawiających ⚠✔ Nieobsługiwane, obejście
Nazwy właściwości Snake-case ⚠✔ Nieobsługiwane, obejście
Obsługa System.Runtime.Serialization atrybutów ⚠✔ Nieobsługiwane, obejście, przykład
MissingMemberHandling ustawienie globalne ⚠✔ Nieobsługiwane, obejście, przykład
JsonObjectAttribute ⚠✔ Nieobsługiwane, obejście
Zezwalaj na nazwy właściwości bez cudzysłowów Nieobsługiwane przez projekt
Zezwalaj na pojedyncze cudzysłowy wokół wartości ciągu Nieobsługiwane przez projekt
Zezwalaj na wartości JSON innych niż ciąg dla właściwości ciągu Nieobsługiwane przez projekt
TypeNameHandling.All ustawienie globalne Nieobsługiwane przez projekt
Obsługa JsonPath zapytań Nieobsługiwane
Konfigurowalne limity Nieobsługiwane
Funkcja systemu Newtonsoft.Json System.Text.Json Równoważne
Deserializacji bez uwzględniania wielkości liter domyślnie ✔️ Ustawienie globalne WłaściwościNameCaseInsensitive
Nazwy właściwości camel-case ✔️ Ustawienie globalne PropertyNamingPolicy
Minimalny znak ucieczki ✔️ Ścisłe znaki ucieczki, konfigurowalne
NullValueHandling.Ignore ustawienie globalne ✔️ Opcja globalna DefaultIgnoreCondition
Zezwalaj na komentarze ✔️ ReadCommentHandling — ustawienie globalne
Zezwalaj na przecinki końcowe ✔️ Ustawienie globalne AllowTrailingCommas
Rejestracja konwertera niestandardowego ✔️ Kolejność pierwszeństwa różni się
Domyślna maksymalna głębokość 64, konfigurowalna ✔️ Domyślna maksymalna głębokość 64, konfigurowalna
PreserveReferencesHandling ustawienie globalne ✔️ Ustawienie globalne ReferenceHandling
Serializowanie lub deserializowanie liczb w cudzysłowie ✔️ NumberHandling ustawienia globalnego [JsonNumberHandling] atrybut
Deserializowanie do niezmiennych klas i struktur ✔️ JsonConstructor, rekordy języka C# 9
Obsługa pól ✔️ Ustawienie globalne IncludeFields, atrybut [JsonInclude]
DefaultValueHandling ustawienie globalne ✔️ Ustawienie globalne DefaultIgnoreCondition
NullValueHandling ustawienie włączone [JsonProperty] ✔️ Atrybut JsonIgnore
DefaultValueHandling ustawienie włączone [JsonProperty] ✔️ Atrybut JsonIgnore
Deserializowanie Dictionary przy użyciu klucza innego niż ciąg ✔️ Obsługiwane
Obsługa zestawów właściwości innych niż publiczne i metody pobierania ✔️ Atrybut JsonInclude
Atrybut [JsonConstructor] ✔️ [JsonConstructor] , atrybut
ReferenceLoopHandling ustawienie globalne ✔️ Ustawienie globalne ReferenceHandling
Wywołania zwrotne ✔️ Wywołania zwrotne
NaN, Infinity, -Infinity ✔️ Obsługiwane
Deserializowanie wartości wyliczenia ciągów ✔️ Deserializowanie wartości wyliczenia ciągów
Obsługa szerokiego zakresu typów ⚠✔ Niektóre typy wymagają konwerterów niestandardowych
Serializacja polimorficzna ⚠✔ Nieobsługiwane, obejście, przykład
Deserializacja polimorficzna ⚠✔ Nieobsługiwane, obejście, przykład
Deserializowanie wnioskowania typu do object właściwości ⚠✔ Nieobsługiwane, obejście, przykład
Deserializowanie literału JSON null do typów wartości innych niż null ⚠✔ Nieobsługiwane, obejście, przykład
Requiredustawienie atrybutu [JsonProperty] ⚠✔ Nieobsługiwane, obejście, przykład
DefaultContractResolver aby zignorować właściwości ⚠✔ Nieobsługiwane, obejście, przykład
DateTimeZoneHandling, DateFormatString ustawienia ⚠✔ Nieobsługiwane, obejście, przykład
JsonConvert.PopulateObject Metoda ⚠✔ Nieobsługiwane, obejście
ObjectCreationHandling ustawienie globalne ⚠✔ Nieobsługiwane, obejście
Dodawanie do kolekcji bez elementów ustawiających ⚠✔ Nieobsługiwane, obejście
Nazwy właściwości Snake-case ⚠✔ Nieobsługiwane, obejście
JsonObjectAttribute ⚠✔ Nieobsługiwane, obejście
Obsługa System.Runtime.Serialization atrybutów Nieobsługiwane
MissingMemberHandling ustawienie globalne Nieobsługiwane
Zezwalaj na nazwy właściwości bez cudzysłowów Nieobsługiwane przez projekt
Zezwalaj na pojedyncze cudzysłowy wokół wartości ciągu Nieobsługiwane przez projekt
Zezwalaj na wartości JSON innych niż ciąg dla właściwości ciągu Nieobsługiwane przez projekt
TypeNameHandling.All ustawienie globalne Nieobsługiwane przez projekt
Obsługa JsonPath zapytań Nieobsługiwane
Konfigurowalne limity Nieobsługiwane

Nie jest to wyczerpująca lista Newtonsoft.Json funkcji. Lista zawiera wiele scenariuszy, które zostały żądane w problemach z usługą GitHub lub wpisami StackOverflow . Jeśli zaimplementujesz obejście jednego ze scenariuszy wymienionych w tym miejscu, które nie ma obecnie przykładowego kodu, a jeśli chcesz udostępnić rozwiązanie, wybierz tę stronę w sekcji Opinie w dolnej części tej strony. Spowoduje to utworzenie problemu w repozytorium GitHub tej dokumentacji i wyświetlenie go również w sekcji Opinie na tej stronie.

Różnice w zachowaniu domyślnym

System.Text.Json jest domyślnie rygorystyczny i unika odgadywania lub interpretacji w imieniu wywołującego, podkreślając deterministyczne zachowanie. Biblioteka została celowo zaprojektowana w ten sposób pod kątem wydajności i zabezpieczeń. Newtonsoft.Json jest domyślnie elastyczny. Ta podstawowa różnica w projekcie stoi za wieloma z następujących specyficznych różnic w zachowaniu domyślnym.

Deserializacji bez uwzględniania wielkości liter

Podczas deserializacji Newtonsoft.Json domyślnie jest dopasowywana nazwa właściwości bez uwzględniania wielkości liter. Wartość domyślna System.Text.Json jest uwzględniana w wielkości liter, co zapewnia lepszą wydajność, ponieważ wykonuje dokładne dopasowanie. Aby uzyskać informacje na temat dopasowywania bez uwzględniania wielkości liter, zobacz Dopasowywanie właściwości bez uwzględniania wielkości liter.

Jeśli używasz System.Text.Json pośrednio przy użyciu ASP.NET Core, nie musisz wykonywać żadnych czynności, aby uzyskać zachowanie takie jak Newtonsoft.Json. ASP.NET Core określa ustawienia nazw właściwości wielbłądowych i dopasowywania bez uwzględniania wielkości liter, gdy używa System.Text.Json.

ASP.NET Core umożliwia również deserializowanie liczb cytowanych domyślnie.

Minimalny znak ucieczki

Podczas serializacji Newtonsoft.Json , jest stosunkowo permissive o puszczanie znaków bez ucieczki. Oznacza to, że nie zastępuje ich \uxxxx miejscem, w którym xxxx jest punkt kodu znaku. W przypadku ich ucieczki, robi to przez emitowanie znaku przed znakiem \ (na przykład " staje się \"). System.Text.Json domyślnie zapewnia ochronę przed atakami skryptowymi między witrynami (XSS) lub atakami polegającymi na ujawnianiu informacji, a także za pomocą sekwencji sześciu znaków. System.Text.Json domyślnie nie ma żadnych znaków innych niż ASCII, więc nie musisz wykonywać żadnych czynności, jeśli używasz StringEscapeHandling.EscapeNonAscii polecenia w systemie Newtonsoft.Json. System.Text.Json domyślnie jest również chroniony znakami wrażliwymi na kod HTML. Aby uzyskać informacje na temat zastępowania zachowania domyślnego System.Text.Json , zobacz Dostosowywanie kodowania znaków.

Komentarze

Podczas deserializacji Newtonsoft.Json domyślnie ignoruje komentarze w formacie JSON. Wartością domyślną System.Text.Json jest zgłaszanie wyjątków dla komentarzy, ponieważ specyfikacja RFC 8259 nie zawiera ich. Aby uzyskać informacje o sposobie zezwalania na komentarze, zobacz Zezwalaj na komentarze i końcowe przecinki.

Przecinki końcowe

Podczas deserializacji Newtonsoft.Json domyślnie ignoruje końcowe przecinki. Ignoruje również wiele przecinków końcowych (na przykład [{"Color":"Red"},{"Color":"Green"},,]). Wartością domyślną System.Text.Json jest zgłaszanie wyjątków dla przecinków końcowych, ponieważ specyfikacja RFC 8259 nie zezwala na nie. Aby uzyskać informacje na temat sposobu System.Text.Json ich akceptowania, zobacz Zezwalaj na komentarze i końcowe przecinki. Nie ma możliwości zezwalania na wiele przecinków końcowych.

Pierwszeństwo rejestracji konwertera

Pierwszeństwo Newtonsoft.Json rejestracji dla konwerterów niestandardowych jest następujące:

Ta kolejność oznacza, że konwerter niestandardowy w Converters kolekcji jest zastępowany przez konwerter zarejestrowany przez zastosowanie atrybutu na poziomie typu. Obie te rejestracje są zastępowane przez atrybut na poziomie właściwości.

Pierwszeństwo System.Text.Json rejestracji dla konwerterów niestandardowych różni się:

  • Atrybut we właściwości
  • Converters Kolekcji
  • Atrybut w typie

Różnica polega na tym, że konwerter niestandardowy w Converters kolekcji zastępuje atrybut na poziomie typu. Celem tego porządku pierwszeństwa jest wprowadzenie zmian w czasie wykonywania zastąpić opcje czasu projektowania. Nie ma możliwości zmiany pierwszeństwa.

Aby uzyskać więcej informacji na temat rejestracji konwertera niestandardowego, zobacz Rejestrowanie konwertera niestandardowego.

Maksymalna głębokość

Najnowsza wersja programu Newtonsoft.Json ma domyślnie maksymalny limit głębokości wynoszący 64. System.Text.Json Ma również domyślny limit 64 i można go skonfigurować, ustawiając wartość JsonSerializerOptions.MaxDepth.

Jeśli używasz System.Text.Json pośrednio przy użyciu ASP.NET Core, domyślny maksymalny limit głębokości wynosi 32. Wartość domyślna jest taka sama jak w przypadku powiązania modelu i jest ustawiona w klasie JsonOptions.

Ciągi JSON (nazwy właściwości i wartości ciągów)

Podczas deserializacji Newtonsoft.Json akceptuje nazwy właściwości otoczone podwójnymi cudzysłowami, apostrofami lub bez cudzysłowów. Akceptuje wartości ciągów otoczone podwójnymi cudzysłowami lub pojedynczymi cudzysłowami. Na przykład Newtonsoft.Json akceptuje następujący kod JSON:

{
  "name1": "value",
  'name2': "value",
  name3: 'value'
}

System.Text.Json Akceptuje tylko nazwy właściwości i wartości ciągów w cudzysłowach, ponieważ ten format jest wymagany przez specyfikację RFC 8259 i jest jedynym formatem uznawanym za prawidłowy kod JSON.

Wartość ujęta w pojedynczy cudzysłów powoduje wyjątek JsonException z następującym komunikatem:

''' is an invalid start of a value.

Wartości inne niż ciągi dla właściwości ciągu

Newtonsoft.Json akceptuje wartości inne niż ciągi, takie jak liczba lub literały true i false, do deserializacji właściwości typu ciąg. Oto przykładowy kod JSON, który Newtonsoft.Json pomyślnie deserializuje do następującej klasy:

{
  "String1": 1,
  "String2": true,
  "String3": false
}
public class ExampleClass
{
    public string String1 { get; set; }
    public string String2 { get; set; }
    public string String3 { get; set; }
}

System.Text.Json nie deserializuje wartości innych niż ciągi we właściwościach ciągu. Odebrana wartość nieciągniowa dla pola ciągu powoduje wyjątek JsonException z następującym komunikatem:

The JSON value could not be converted to System.String.

Scenariusze korzystające z narzędzia JsonSerializer

Niektóre z poniższych scenariuszy nie są obsługiwane przez wbudowane funkcje, ale możliwe są obejścia. Obejścia to konwertery niestandardowe, które mogą nie zapewniać pełnej równoważności z funkcjami Newtonsoft.Json . W przypadku niektórych z nich przykładowy kod jest dostarczany jako przykłady. Jeśli korzystasz z tych Newtonsoft.Json funkcji, migracja będzie wymagać modyfikacji modeli obiektów platformy .NET lub innych zmian kodu.

W przypadku niektórych z poniższych scenariuszy obejścia nie są praktyczne ani możliwe. Jeśli korzystasz z tych Newtonsoft.Json funkcji, migracja nie będzie możliwa bez istotnych zmian.

Zezwalaj na liczby w cudzysłowie lub zapisuj je

Newtonsoft.Json może serializować lub deserializować liczby reprezentowane przez ciągi JSON (otoczone cudzysłowami). Na przykład może zaakceptować: {"DegreesCelsius":"23"} zamiast {"DegreesCelsius":23}. Aby włączyć to zachowanie w systemie System.Text.Json, ustaw JsonSerializerOptions.NumberHandling na WriteAsString lub AllowReadingFromString, lub użyj atrybutu [JsonNumberHandling].

Jeśli używasz System.Text.Json pośrednio przy użyciu ASP.NET Core, nie musisz wykonywać żadnych czynności, aby uzyskać zachowanie takie jak Newtonsoft.Json. ASP.NET Core określa wartości domyślne sieci Web, gdy używa System.Text.Jsonwartości , a wartości domyślne sieci Web zezwalają na liczby cytowane.

Aby uzyskać więcej informacji, zobacz Zezwalanie na liczby w cudzysłowie lub zapisywanie ich w cudzysłowie.

Określanie konstruktora do użycia podczas deserializacji

Atrybut Newtonsoft.Json[JsonConstructor] umożliwia określenie konstruktora do wywołania podczas deserializacji do klasy POCO.

System.Text.Jsonma również atrybut [JsonConstructor]. Aby uzyskać więcej informacji, zobacz Niezmienne typy i rekordy.

Warunkowe ignorowanie właściwości

Newtonsoft.Json Program ma kilka sposobów warunkowego ignorowania właściwości serializacji lub deserializacji:

  • DefaultContractResolver Umożliwia wybranie właściwości do uwzględnienia lub zignorowania na podstawie dowolnych kryteriów.
  • Ustawienia NullValueHandling i DefaultValueHandlingJsonSerializerSettings umożliwiają określenie, że wszystkie właściwości null-value lub default-value powinny być ignorowane.
  • Ustawienia NullValueHandling i DefaultValueHandling w atrybucie [JsonProperty] umożliwiają określenie poszczególnych właściwości, które powinny być ignorowane po ustawieniu wartości null lub wartości domyślnej.

System.Text.Json Udostępnia następujące sposoby ignorowania właściwości lub pól podczas serializacji:

Ponadto w wersjach .NET 7 i nowszych można dostosować kontrakt JSON, aby ignorować właściwości na podstawie dowolnych kryteriów. Aby uzyskać więcej informacji, zobacz Kontrakty niestandardowe.

Te opcje nie pozwalają ignorować wybranych właściwości na podstawie dowolnych kryteriów ocenianych w czasie wykonywania.

Pola publiczne i inne niż publiczne

Newtonsoft.Json może serializować i deserializować pola, a także właściwości.

W System.Text.Jsonsystemie użyj ustawienia globalnego JsonSerializerOptions.IncludeFields lub atrybutu [JsonInclude], aby uwzględnić pola publiczne podczas serializacji lub deserializacji. Aby zapoznać się z przykładem, zobacz Dołączanie pól.

Zachowywanie odwołań do obiektów i pętle obsługi

Domyślnie Newtonsoft.Json serializuje według wartości. Jeśli na przykład obiekt zawiera dwie właściwości, które zawierają odwołanie do tego samego Person obiektu, wartości właściwości tego Person obiektu są zduplikowane w formacie JSON.

Newtonsoft.JsonPreserveReferencesHandling ma ustawienie, JsonSerializerSettings które umożliwia serializację według odwołania:

  • Metadane identyfikatora są dodawane do pliku JSON utworzonego dla pierwszego Person obiektu.
  • Kod JSON utworzony dla drugiego Person obiektu zawiera odwołanie do tego identyfikatora zamiast wartości właściwości.

Newtonsoft.Json Ma ReferenceLoopHandling również ustawienie, które pozwala ignorować odwołania cykliczne, a nie zgłaszać wyjątku.

Aby zachować odwołania i obsłużyć odwołania cykliczne w elemencie System.Text.Json, ustaw wartość JsonSerializerOptions.ReferenceHandlerPreserve. To ustawienie jest równoważne w elemencie ReferenceHandler.PreserveNewtonsoft.JsonPreserveReferencesHandling = PreserveReferencesHandling.All .

Opcja ReferenceHandler.IgnoreCycles ma zachowanie podobne do Newtonsoft.JsonReferenceLoopHandling.Ignore. Jedną z różnic jest to, że implementacja System.Text.Json zastępuje pętle odwołań tokenem null JSON zamiast ignorować odwołanie do obiektu. Aby uzyskać więcej informacji, zobacz Ignoruj odwołania cykliczne.

Podobnie jak w przypadku Newtonsoft.Jsonklasy ReferenceResolver, System.Text.Json.Serialization.ReferenceResolver klasa definiuje zachowanie zachowania odwołań do serializacji i deserializacji. Utwórz klasę pochodną, aby określić zachowanie niestandardowe. Aby zapoznać się z przykładem, zobacz GuidReferenceResolver.

Niektóre powiązane Newtonsoft.Json funkcje nie są obsługiwane:

Aby uzyskać więcej informacji, zobacz Zachowywanie odwołań i obsługa odwołań cyklicznych.

Słownik z kluczem nieciągowym

Zarówno kolekcje, jak Newtonsoft.Json i System.Text.Json obsługują kolekcje typu Dictionary<TKey, TValue>. Jednak w systemie System.Text.JsonTKey musi być typem pierwotnym, a nie typem niestandardowym. Aby uzyskać więcej informacji, zobacz Obsługiwane typy kluczy.

Uwaga

Deserializowanie w Dictionary<TKey, TValue> miejscu, w którym TKey jest wpisywane jako inne niż string może spowodować wprowadzenie luki w zabezpieczeniach w aplikacji zużywanej. Aby uzyskać więcej informacji, zobacz dotnet/runtime#4761.

Typy bez wbudowanej obsługi

System.Text.Json nie zapewnia wbudowanej obsługi następujących typów:

Konwertery niestandardowe można zaimplementować dla typów, które nie mają wbudowanej obsługi.

Serializacja polimorficzna

Newtonsoft.Json program automatycznie wykonuje serializacji polimorficznej. Począwszy od platformy .NET 7, System.Text.Json obsługuje serializacji polimorficznej za pomocą atrybutu JsonDerivedTypeAttribute . Aby uzyskać więcej informacji, zobacz Serializowanie właściwości klas pochodnych.

Deserializacja polimorficzna

Newtonsoft.JsonTypeNameHandling Ma ustawienie, które dodaje metadane nazwy typu do formatu JSON podczas serializacji. Używa metadanych podczas deserializacji do deserializacji polimorficznej. Począwszy od platformy .NET 7, System.Text.Json opiera się na dyskryminujących informacjach o typie w celu przeprowadzenia deserializacji polimorficznej. Te metadane są emitowane w formacie JSON, a następnie używane podczas deserializacji w celu określenia, czy deserializować typ podstawowy, czy typ pochodny. Aby uzyskać więcej informacji, zobacz Serializowanie właściwości klas pochodnych.

Aby zapewnić obsługę deserializacji polimorficznej w starszych wersjach platformy .NET, utwórz konwerter podobny do przykładu w temacie How to write custom converters (Jak pisać konwertery niestandardowe).

Deserializowanie wartości wyliczenia ciągów

Domyślnie System.Text.Json nie obsługuje deserializacji wartości wyliczenia ciągów, natomiast Newtonsoft.Json nie. Na przykład następujący kod zgłasza błąd JsonException:

string json = "{ \"Text\": \"Hello\", \"Enum\": \"Two\" }";
var _ = JsonSerializer.Deserialize<MyObj>(json); // Throws exception.

class MyObj
{
    public string Text { get; set; } = "";
    public MyEnum Enum { get; set; }
}

enum MyEnum
{
    One,
    Two,
    Three
}

Można jednak włączyć deserializacji wartości wyliczenia ciągów przy użyciu konwertera JsonStringEnumConverter . Aby uzyskać więcej informacji, zobacz wyliczenia jako ciągi.

Deserializacja właściwości obiektu

Gdy Newtonsoft.Json deserializuje wartość Object, to:

  • Wywnioskuje typ wartości pierwotnych w ładunku JSON (innym niż null) i zwraca przechowywany stringobiekt , , longdouble, booleanlub DateTime jako obiekt w polu. Wartości pierwotne to pojedyncze wartości JSON, takie jak liczba JSON, ciąg, true, falselub null.
  • Zwraca wartość JObject lub JArray dla wartości złożonych w ładunku JSON. Wartości złożone to kolekcje par klucz-wartość JSON w nawiasach klamrowych ({}) lub listach wartości w nawiasach kwadratowych ([]). Właściwości i wartości w nawiasach klamrowych lub nawiasach mogą mieć dodatkowe właściwości lub wartości.
  • Zwraca odwołanie o wartości null, gdy ładunek ma null literał JSON.

System.Text.Json przechowuje pola JsonElement zarówno dla wartości pierwotnych, jak i złożonych przy każdym deserializacji do Object, na przykład:

  • Właściwość object .
  • Wartość słownika object .
  • object Wartość tablicy.
  • Katalog główny object.

Jednak traktuje null to samo, co Newtonsoft.Json i zwraca odwołanie o wartości null, System.Text.Json gdy ładunek ma null literał JSON w nim.

Aby zaimplementować wnioskowanie typu dla object właściwości, utwórz konwerter podobny do przykładu w temacie How to write custom converters (Jak pisać konwertery niestandardowe).

Deserializowanie wartości null do typu niepustego

Newtonsoft.Json Nie zgłasza wyjątku w następującym scenariuszu:

  • NullValueHandling jest ustawiona na Ignore, i
  • Podczas deserializacji kod JSON zawiera wartość null dla typu wartości innej niż null.

W tym samym scenariuszu System.Text.Json zgłasza wyjątek. (Odpowiednie ustawienie obsługi wartości null w pliku System.Text.Json to JsonSerializerOptions.IgnoreNullValues = true.)

Jeśli jesteś właścicielem typu docelowego, najlepszym obejściem jest, aby właściwość, o której mowa, dopuszczała wartość null (na przykład zmień wartość int na int?).

Innym obejściem jest utworzenie konwertera dla typu, takiego jak poniższy przykład, który obsługuje wartości null dla DateTimeOffset typów:

using System.Text.Json;
using System.Text.Json.Serialization;

namespace SystemTextJsonSamples
{
    public class DateTimeOffsetNullHandlingConverter : JsonConverter<DateTimeOffset>
    {
        public override DateTimeOffset Read(
            ref Utf8JsonReader reader,
            Type typeToConvert,
            JsonSerializerOptions options) =>
            reader.TokenType == JsonTokenType.Null
                ? default
                : reader.GetDateTimeOffset();

        public override void Write(
            Utf8JsonWriter writer,
            DateTimeOffset dateTimeValue,
            JsonSerializerOptions options) =>
            writer.WriteStringValue(dateTimeValue);
    }
}

Zarejestruj ten konwerter niestandardowy przy użyciu atrybutu we właściwości lub dodając konwerter do Converters kolekcji.

Uwaga: Powyższy konwerter obsługuje wartości null inaczej niż Newtonsoft.Json w przypadku obiektów POCO określających wartości domyślne. Załóżmy na przykład, że następujący kod reprezentuje obiekt docelowy:

public class WeatherForecastWithDefault
{
    public WeatherForecastWithDefault()
    {
        Date = DateTimeOffset.Parse("2001-01-01");
        Summary = "No summary";
    }
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string Summary { get; set; }
}

Załóżmy, że następujący kod JSON jest deserializowany przy użyciu powyższego konwertera:

{
  "Date": null,
  "TemperatureCelsius": 25,
  "Summary": null
}

Po deserializacji Date właściwość ma wartość 1/1/0001 (default(DateTimeOffset)), czyli wartość ustawioną w konstruktorze jest zastępowana. Biorąc pod uwagę te same wartości POCO i JSON, Newtonsoft.Json deserializacja pozostawiłaby wartość 1/1/2001 we Date właściwości .

Deserializowanie do niezmiennych klas i struktur

Newtonsoft.Json program może wykonać deserializacji do niezmiennych klas i struktur, ponieważ może używać konstruktorów, które mają parametry.

W System.Text.Jsonpliku użyj atrybutu [JsonConstructor], aby określić użycie konstruktora sparametryzowanego. Rekordy w języku C# 9 są również niezmienne i są obsługiwane jako cele deserializacji. Aby uzyskać więcej informacji, zobacz Niezmienne typy i rekordy.

Wymagane właściwości

W Newtonsoft.Jsonpliku należy określić, że właściwość jest wymagana przez ustawienie Required atrybutu [JsonProperty] . Newtonsoft.Json zgłasza wyjątek, jeśli w formacie JSON nie zostanie odebrana żadna wartość dla właściwości oznaczonej jako wymagana.

Począwszy od platformy .NET 7, można użyć modyfikatora języka C# required lub atrybutu JsonRequiredAttribute w wymaganej właściwości. System.Text.Json zgłasza wyjątek, jeśli ładunek JSON nie zawiera wartości dla oznaczonej właściwości. Aby uzyskać więcej informacji, zobacz Wymagane właściwości.

System.Text.Json nie zgłasza wyjątku, jeśli żadna wartość nie zostanie odebrana dla jednej z właściwości typu docelowego. Jeśli na przykład masz klasę WeatherForecast :

public class WeatherForecast
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}

Następujący kod JSON jest deserializowany bez błędu:

{
    "TemperatureCelsius": 25,
    "Summary": "Hot"
}

Aby deserializacja nie powiodła się, jeśli żadna właściwość nie Date znajduje się w formacie JSON, wybierz jedną z następujących opcji:

Poniższy przykładowy kod konwertera zgłasza wyjątek, jeśli Date właściwość nie jest ustawiona po zakończeniu deserializacji:

using System.Text.Json;
using System.Text.Json.Serialization;

namespace SystemTextJsonSamples
{
    public class WeatherForecastRequiredPropertyConverter : JsonConverter<WeatherForecast>
    {
        public override WeatherForecast Read(
            ref Utf8JsonReader reader,
            Type type,
            JsonSerializerOptions options)
        {
            // Don't pass in options when recursively calling Deserialize.
            WeatherForecast forecast = JsonSerializer.Deserialize<WeatherForecast>(ref reader)!;

            // Check for required fields set by values in JSON
            return forecast!.Date == default
                ? throw new JsonException("Required property not received in the JSON")
                : forecast;
        }

        public override void Write(
            Utf8JsonWriter writer,
            WeatherForecast forecast, JsonSerializerOptions options)
        {
            // Don't pass in options when recursively calling Serialize.
            JsonSerializer.Serialize(writer, forecast);
        }
    }
}

Zarejestruj ten konwerter niestandardowy, dodając konwerter do kolekcji JsonSerializerOptions.Converters .

Ten wzorzec cyklicznego wywoływania konwertera wymaga zarejestrowania konwertera przy użyciu JsonSerializerOptionsmetody , a nie przy użyciu atrybutu . W przypadku zarejestrowania konwertera przy użyciu atrybutu konwerter niestandardowy rekursywnie wywołuje się samodzielnie. Wynikiem jest nieskończona pętla, która kończy się wyjątkiem przepełnienia stosu.

Podczas rejestrowania konwertera przy użyciu obiektu options unikaj nieskończonej pętli, nie przekazując obiektu options podczas cyklicznego wywoływania Serialize lub Deserialize. Obiekt options zawiera Converters kolekcję. Jeśli przekazujesz go do Serialize metody lub Deserialize, niestandardowy konwerter wywołuje się do samego siebie, tworząc nieskończoną pętlę, która powoduje wyjątek przepełnienia stosu. Jeśli opcje domyślne nie są możliwe, utwórz nowe wystąpienie opcji przy użyciu potrzebnych ustawień. Takie podejście będzie powolne, ponieważ każde nowe wystąpienie będzie buforowane niezależnie.

Istnieje alternatywny wzorzec, który może używać JsonConverterAttribute rejestracji w klasie do konwersji. W tym podejściu kod konwertera wywołuje Serialize lub Deserialize w klasie, która pochodzi z klasy, która ma zostać przekonwertowana. Klasa pochodna nie ma JsonConverterAttribute do niej zastosowania. W poniższym przykładzie tej alternatywy:

  • WeatherForecastWithRequiredPropertyConverterAttribute jest klasą do deserializacji i zastosowana JsonConverterAttribute do niej.
  • WeatherForecastWithoutRequiredPropertyConverterAttribute jest klasą pochodną, która nie ma atrybutu konwertera.
  • Kod w wywołaniach Serialize konwertera i Deserialize włączony WeatherForecastWithoutRequiredPropertyConverterAttribute , aby uniknąć nieskończonej pętli. Istnieje koszt wydajności dla tej metody serializacji ze względu na dodatkowe utworzenie wystąpienia obiektu i skopiowanie wartości właściwości.

WeatherForecast* Oto typy:

[JsonConverter(typeof(WeatherForecastRequiredPropertyConverterForAttributeRegistration))]
public class WeatherForecastWithRequiredPropertyConverterAttribute
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}

public class WeatherForecastWithoutRequiredPropertyConverterAttribute :
    WeatherForecastWithRequiredPropertyConverterAttribute
{
}

A oto konwerter:

using System.Text.Json;
using System.Text.Json.Serialization;

namespace SystemTextJsonSamples
{
    public class WeatherForecastRequiredPropertyConverterForAttributeRegistration :
        JsonConverter<WeatherForecastWithRequiredPropertyConverterAttribute>
    {
        public override WeatherForecastWithRequiredPropertyConverterAttribute Read(
            ref Utf8JsonReader reader,
            Type type,
            JsonSerializerOptions options)
        {
            // OK to pass in options when recursively calling Deserialize.
            WeatherForecastWithRequiredPropertyConverterAttribute forecast =
                JsonSerializer.Deserialize<WeatherForecastWithoutRequiredPropertyConverterAttribute>(
                    ref reader,
                    options)!;

            // Check for required fields set by values in JSON.
            return forecast!.Date == default
                ? throw new JsonException("Required property not received in the JSON")
                : forecast;
        }

        public override void Write(
            Utf8JsonWriter writer,
            WeatherForecastWithRequiredPropertyConverterAttribute forecast,
            JsonSerializerOptions options)
        {
            var weatherForecastWithoutConverterAttributeOnClass =
                new WeatherForecastWithoutRequiredPropertyConverterAttribute
                {
                    Date = forecast.Date,
                    TemperatureCelsius = forecast.TemperatureCelsius,
                    Summary = forecast.Summary
                };

            // OK to pass in options when recursively calling Serialize.
            JsonSerializer.Serialize(
                writer,
                weatherForecastWithoutConverterAttributeOnClass,
                options);
        }
    }
}

Wymagany konwerter właściwości wymaga dodatkowej logiki, jeśli musisz obsługiwać atrybuty, takie jak [JsonIgnore] lub różne opcje, takie jak kodery niestandardowe. Ponadto przykładowy kod nie obsługuje właściwości, dla których wartość domyślna jest ustawiana w konstruktorze. To podejście nie rozróżnia następujących scenariuszy:

  • Brak właściwości w formacie JSON.
  • Właściwość typu innego niż null jest obecna w formacie JSON, ale wartość jest wartością domyślną dla typu, na przykład zero dla .int
  • Właściwość typu wartości dopuszczanej do wartości null jest obecna w formacie JSON, ale wartość ma wartość null.

Uwaga

Jeśli używasz z System.Text.Json kontrolera ASP.NET Core, możesz użyć [Required] atrybutu we właściwościach klasy modelu zamiast implementowania konwertera System.Text.Json .

Określanie formatu daty

Newtonsoft.Json Udostępnia kilka sposobów kontrolowania DateTime sposobu serializacji i deserializacji właściwości i DateTimeOffset typów:

  • Ustawienie DateTimeZoneHandling może służyć do serializacji wszystkich DateTime wartości jako dat UTC.
  • Ustawienie DateFormatString i DateTime konwertery mogą służyć do dostosowywania formatu ciągów daty.

System.Text.Json obsługuje standard ISO 8601-1:2019, w tym profil RFC 3339. Ten format jest powszechnie stosowany, jednoznaczny i precyzyjnie wykonuje rundy. Aby użyć dowolnego innego formatu, utwórz konwerter niestandardowy. Na przykład następujące konwertery serializują i deserializują kod JSON, który używa formatu epoki Unix z przesunięciem strefy czasowej lub bez tego przesunięcia (wartości, takie jak /Date(1590863400000-0700)/ lub /Date(1590863400000)/):

sealed class UnixEpochDateTimeOffsetConverter : JsonConverter<DateTimeOffset>
{
    static readonly DateTimeOffset s_epoch = new(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
    static readonly Regex s_regex = new("^/Date\\(([+-]*\\d+)([+-])(\\d{2})(\\d{2})\\)/$", RegexOptions.CultureInvariant);

    public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        string formatted = reader.GetString()!;
        Match match = s_regex.Match(formatted);

        if (
                !match.Success
                || !long.TryParse(match.Groups[1].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out long unixTime)
                || !int.TryParse(match.Groups[3].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out int hours)
                || !int.TryParse(match.Groups[4].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out int minutes))
        {
            throw new JsonException();
        }

        int sign = match.Groups[2].Value[0] == '+' ? 1 : -1;
        TimeSpan utcOffset = new(hours * sign, minutes * sign, 0);

        return s_epoch.AddMilliseconds(unixTime).ToOffset(utcOffset);
    }

    public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options)
    {
        long unixTime = Convert.ToInt64((value - s_epoch).TotalMilliseconds);
        TimeSpan utcOffset = value.Offset;

        string formatted = string.Create(CultureInfo.InvariantCulture, $"/Date({unixTime}{(utcOffset >= TimeSpan.Zero ? "+" : "-")}{utcOffset:hhmm})/");

        writer.WriteStringValue(formatted);
    }
}
sealed class UnixEpochDateTimeConverter : JsonConverter<DateTime>
{
    static readonly DateTime s_epoch = new(1970, 1, 1, 0, 0, 0);
    static readonly Regex s_regex = new("^/Date\\(([+-]*\\d+)\\)/$", RegexOptions.CultureInvariant);

    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        string formatted = reader.GetString()!;
        Match match = s_regex.Match(formatted);

        if (
                !match.Success
                || !long.TryParse(match.Groups[1].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out long unixTime))
        {
            throw new JsonException();
        }

        return s_epoch.AddMilliseconds(unixTime);
    }

    public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
    {
        long unixTime = Convert.ToInt64((value - s_epoch).TotalMilliseconds);

        string formatted = string.Create(CultureInfo.InvariantCulture, $"/Date({unixTime})/");
        writer.WriteStringValue(formatted);
    }
}

Aby uzyskać więcej informacji, zobacz Obsługa funkcji DateTime i DateTimeOffset w systemie System.Text.Json.

Wywołania zwrotne

Newtonsoft.Json umożliwia wykonywanie kodu niestandardowego w kilku punktach w procesie serializacji lub deserializacji:

  • OnDeserializing (gdy zaczyna się deserializować obiekt)
  • OnDeserialized (po zakończeniu deserializacji obiektu)
  • OnSerializing (gdy rozpoczyna się serializowanie obiektu)
  • OnSerialized (po zakończeniu serializacji obiektu)

System.Text.Json uwidacznia te same powiadomienia podczas serializacji i deserializacji. Aby ich używać, zaimplementuj co najmniej jeden z następujących interfejsów z System.Text.Json.Serialization przestrzeni nazw:

Oto przykład, który sprawdza właściwość null i zapisuje komunikaty na początku i na końcu serializacji i deserializacji:

using System.Text.Json;
using System.Text.Json.Serialization;

namespace Callbacks
{
    public class WeatherForecast : 
        IJsonOnDeserializing, IJsonOnDeserialized, 
        IJsonOnSerializing, IJsonOnSerialized
    {
        public DateTime Date { get; set; }
        public int TemperatureCelsius { get; set; }
        public string? Summary { get; set; }

        void IJsonOnDeserializing.OnDeserializing() => Console.WriteLine("\nBegin deserializing");
        void IJsonOnDeserialized.OnDeserialized()
        {
            Validate();
            Console.WriteLine("Finished deserializing");
        }
        void IJsonOnSerializing.OnSerializing()
        {
            Console.WriteLine("Begin serializing");
            Validate();
        }
        void IJsonOnSerialized.OnSerialized() => Console.WriteLine("Finished serializing");

        private void Validate()
        {
            if (Summary is null)
            {
                Console.WriteLine("The 'Summary' property is 'null'.");
            }
        }
    }

    public class Program
    {
        public static void Main()
        {
            var weatherForecast = new WeatherForecast
            {
                Date = DateTime.Parse("2019-08-01"),
                TemperatureCelsius = 25,
            };

            string jsonString = JsonSerializer.Serialize(weatherForecast);
            Console.WriteLine(jsonString);

            weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonString);
            Console.WriteLine($"Date={weatherForecast?.Date}");
            Console.WriteLine($"TemperatureCelsius={weatherForecast?.TemperatureCelsius}");
            Console.WriteLine($"Summary={weatherForecast?.Summary}");
        }
    }
}
// output:
//Begin serializing
//The 'Summary' property is 'null'.
//Finished serializing
//{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":null}

//Begin deserializing
//The 'Summary' property is 'null'.
//Finished deserializing
//Date=8/1/2019 12:00:00 AM
//TemperatureCelsius = 25
//Summary=

Kod OnDeserializing nie ma dostępu do nowego wystąpienia POCO. Aby manipulować nowym wystąpieniem POCO na początku deserializacji, umieść ten kod w konstruktorze POCO.

Metody ustawiania i pobierania właściwości innych niż publiczne

Newtonsoft.Json może używać prywatnych i wewnętrznych modułów ustawiających i pobierających za pośrednictwem atrybutu JsonProperty .

System.Text.JsonObsługuje moduły ustawiania właściwości prywatnych i wewnętrznych oraz metody pobierania za pośrednictwem atrybutu [JsonInclude]. Aby uzyskać przykładowy kod, zobacz Metody dostępu do właściwości innych niż publiczne.

Wypełnianie istniejących obiektów

Metoda JsonConvert.PopulateObject w Newtonsoft.Json deserializuje dokument JSON do istniejącego wystąpienia klasy, zamiast tworzyć nowe wystąpienie. System.Text.Json zawsze tworzy nowe wystąpienie typu docelowego przy użyciu domyślnego publicznego konstruktora bez parametrów. Konwertery niestandardowe mogą deserializacji do istniejącego wystąpienia.

Ponowne użycie, a nie zastępowanie właściwości

Począwszy od platformy .NET 8, System.Text.Json obsługuje ponowne uzyskiwanie zainicjowanych właściwości, a nie ich zastępowanie. Istnieją pewne różnice w zachowaniu, które można przeczytać w propozycji interfejsu API.

Aby uzyskać więcej informacji, zobacz Wypełnianie zainicjowanych właściwości.

Ustawienie ObjectCreationHandling w programie Newtonsoft.Json umożliwia określenie, że obiekty we właściwościach powinny być ponownie używane, a nie zastępowane podczas deserializacji. System.Text.Json zawsze zastępuje obiekty we właściwościach. Konwertery niestandardowe mogą zapewnić tę funkcję lub można uaktualnić do platformy .NET 8, która zapewnia funkcjonalność wypełniania.

Wypełnianie właściwości bez ustawiających

Począwszy od platformy .NET 8, System.Text.Json obsługuje wypełnianie właściwości, w tym te, które nie mają zestawu. Aby uzyskać więcej informacji, zobacz Wypełnianie zainicjowanych właściwości.

Podczas deserializacji Newtonsoft.Json dodaje obiekty do kolekcji, nawet jeśli właściwość nie ma elementu ustawianego. System.Text.Json ignoruje właściwości, które nie mają ustawiaczy. Konwertery niestandardowe mogą udostępniać tę funkcję lub można uaktualnić do platformy .NET 8, która może wypełniać właściwości tylko do odczytu.

Zasady nazewnictwa przypadków węża

System.Text.Json zawiera wbudowane zasady nazewnictwa dla przypadku węża. Istnieją jednak pewne różnice Newtonsoft.Json w zachowaniu dla niektórych danych wejściowych. W poniższej tabeli przedstawiono niektóre z tych różnic podczas konwertowania danych wejściowych przy użyciu JsonNamingPolicy.SnakeCaseLower zasad.

Dane wejściowe Newtonsoft.Json Wynik System.Text.Json Wynik
"AB1" "a_b1" "ab1"
"SHA512Managed" "sh_a512_managed" "sha512_managed"
"abc123DEF456" "abc123_de_f456" "abc123_def456"
"KEBAB-CASE" "keba_b-_case" "kebab-case"

Jedynymi wbudowanymi zasadami System.Text.Json nazewnictwa właściwości jest przypadek camel. Newtonsoft.Json może konwertować nazwy właściwości na przypadek węża. Niestandardowe zasady nazewnictwa mogą zapewnić tę funkcję lub uaktualnić do platformy .NET 8 lub nowszej, która obejmuje wbudowane zasady nazewnictwa przypadków węża.

Atrybuty System.Runtime.Serialization

System.Runtime.Serializationatrybuty, takie jak DataContractAttribute, DataMemberAttributei IgnoreDataMemberAttribute umożliwiają zdefiniowanie kontraktu danych. Kontrakt danych to formalna umowa między usługą a klientem, który abstrakcyjnie opisuje dane do wymiany. Kontrakt danych dokładnie definiuje, które właściwości są serializowane do wymiany.

System.Text.Json nie ma wbudowanej obsługi tych atrybutów. Jednak począwszy od platformy .NET 7, można użyć niestandardowego rozpoznawania typów w celu dodania obsługi. Aby zapoznać się z przykładem, zobacz ZCS. DataContractResolver.

Liczby ósemkowe

Newtonsoft.Json traktuje liczby z zerem wiodącym jako liczby ósemkowe. System.Text.Json nie zezwala na zera wiodące, ponieważ specyfikacja RFC 8259 nie zezwala na nie.

Obsługa brakujących elementów członkowskich

Jeśli plik JSON, który jest deserializowany, zawiera właściwości, których brakuje w typie docelowym, można skonfigurować tak, Newtonsoft.Json aby zgłaszać wyjątki. Domyślnie System.Text.Json ignoruje dodatkowe właściwości w formacie JSON, z wyjątkiem użycia atrybutu [JsonExtensionData].

W programie .NET 8 lub nowszym można ustawić preferencje dotyczące tego, czy pominąć lub uniemożliwić niezamapowane właściwości JSON przy użyciu jednej z następujących metod:

JsonObjectAttribute

Newtonsoft.Json ma atrybut , JsonObjectAttributektóry można zastosować na poziomie typu, aby kontrolować, które elementy członkowskie są serializowane, jak null są obsługiwane wartości i czy wszystkie elementy członkowskie są wymagane. System.Text.Json nie ma równoważnego atrybutu, który można zastosować w typie. W przypadku niektórych zachowań, takich jak null obsługa wartości, można skonfigurować to samo zachowanie na poziomie globalnym JsonSerializerOptions lub indywidualnie dla każdej właściwości.

Rozważmy następujący przykład, który używa Newtonsoft.Json.JsonObjectAttribute metody , aby określić, że wszystkie null właściwości powinny być ignorowane:

[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)]
public class Person { ... }

W System.Text.Jsonprogramie można ustawić zachowanie dla wszystkich typów i właściwości:

JsonSerializerOptions options = new()
{
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};

string json = JsonSerializer.Serialize<Person>(person, options);

Możesz też ustawić zachowanie dla każdej właściwości oddzielnie:

public class Person
{
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Name { get; set; }

    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public int? Age { get; set; }
}

Następnie rozważmy następujący przykład, który używa Newtonsoft.Json.JsonObjectAttribute polecenia , aby określić, że wszystkie właściwości składowych muszą być obecne w formacie JSON:

[JsonObject(ItemRequired = Required.Always)]
public class Person { ... }

To samo zachowanie System.Text.Json można osiągnąć, dodając modyfikator języka C# required lub do JsonRequiredAttributekażdej właściwości. Aby uzyskać więcej informacji, zobacz Wymagane właściwości.

public class Person
{
    [JsonRequired]
    public string? Name { get; set; }

    public required int? Age { get; set; }
}

TraceWriter

Newtonsoft.Json umożliwia debugowanie przy użyciu elementu , TraceWriter aby wyświetlić dzienniki generowane przez serializacji lub deserializacji. System.Text.Json nie wykonuje rejestrowania.

JsonDocument i JsonElement w porównaniu do JToken (na przykład JObject, JArray)

System.Text.Json.JsonDocument Umożliwia analizowanie i tworzenie modelu obiektów dokumentów tylko do odczytu (DOM) z istniejących ładunków JSON. Dom zapewnia losowy dostęp do danych w ładunku JSON. Dostęp do elementów JSON, które tworzą ładunek, można uzyskać za pośrednictwem JsonElement typu . Typ JsonElement udostępnia interfejsy API do konwertowania tekstu JSON na typowe typy platformy .NET. JsonDocument uwidacznia RootElement właściwość.

Począwszy od platformy .NET 6, można przeanalizować i skompilować modyfikowalny dom z istniejących ładunków JSON przy użyciu JsonNode typu i innych typów w System.Text.Json.Nodes przestrzeni nazw. Aby uzyskać więcej informacji, zobacz Use JsonNode.

JsonDocument to IDisposable

JsonDocument tworzy widok danych w pamięci w buforze w puli. W związku z Newtonsoft.JsonJsonDocument tym, w przeciwieństwie do JObject metody , JArray typ implementuje IDisposable i musi być używany wewnątrz bloku using. Aby uzyskać więcej informacji, zobacz JsonDocument is IDisposable (Dokument JsonDocument to IDisposable).

Dokument JsonDocument jest tylko do odczytu

Dom System.Text.Json nie może dodawać, usuwać ani modyfikować elementów JSON. Został zaprojektowany w ten sposób pod kątem wydajności i zmniejszenia alokacji na potrzeby analizowania typowych rozmiarów ładunków JSON (czyli < 1 MB).

JsonElement to struktura unii

JsonDocument Uwidacznia RootElement jako właściwość typu JsonElement, która jest typem struktury unii, który obejmuje dowolny element JSON. Newtonsoft.Jsonużywa dedykowanych typów hierarchicznych, takich jak JObject,JArrayJToken i tak dalej. JsonElement to, co można wyszukiwać i wyliczać, i można użyć JsonElement do materializowania elementów JSON w typach platformy .NET.

Począwszy od platformy .NET 6, można użyć JsonNode typów i typów w System.Text.Json.Nodes przestrzeni nazw, która odpowiada elementom JObject,JArray i JToken. Aby uzyskać więcej informacji, zobacz Use JsonNode.

Jak wyszukiwać elementy podrzędne JsonDocument i JsonElement

Wyszukuje tokeny JSON używające JObject lub JArray z Newtonsoft.Json nich zwykle są stosunkowo szybkie, ponieważ są one wyszukiwane w pewnym słowniku. Dla porównania wyszukiwanie JsonElement wymaga sekwencyjnego wyszukiwania właściwości i dlatego jest stosunkowo powolne (na przykład w przypadku używania metody TryGetProperty). System.Text.Json program został zaprojektowany tak, aby zminimalizować czas analizy początkowej, a nie czas wyszukiwania. Aby uzyskać więcej informacji, zobacz How to search a JsonDocument and JsonElement for sub-elements (Jak wyszukiwać elementy podrzędne JsonDocument i JsonElement).

Utf8JsonReader a JsonTextReader

System.Text.Json.Utf8JsonReaderto wysokowydajny, niski przydział, czytnik tylko do przodu dla tekstu JSON zakodowanego w formacie UTF-8, odczytywany z bajtu >ReadOnlySpan<lub ReadOnlySequence<bajtu.> Jest Utf8JsonReader to typ niskiego poziomu, który może służyć do tworzenia niestandardowych parserów i deserializatorów.

Utf8JsonReader to struktura ref

Element JsonTextReader in Newtonsoft.Json jest klasą. Typ Utf8JsonReader różni się w tym, że jest to struktura ref. Aby uzyskać więcej informacji, zobacz ograniczenia struktury ref dla utf8JsonReader.

Odczytywanie wartości null do typów wartości dopuszczanych do wartości null

Newtonsoft.Json Udostępnia interfejsy API, które zwracają Nullable<T>element , na przykład ReadAsBoolean, który obsługuje NullTokenType element za Ciebie, zwracając element bool?. Wbudowane System.Text.Json interfejsy API zwracają tylko typy wartości innych niż null. Aby uzyskać więcej informacji, zobacz Odczyt wartości null do typów wartości dopuszczanych do wartości null.

Wiele obiektów docelowych do odczytywania kodu JSON

Jeśli musisz nadal korzystać Newtonsoft.Json z niektórych platform docelowych, możesz mieć wiele implementacji i mieć dwie implementacje. Nie jest to jednak proste i wymagałoby duplikowania niektórych #ifdefs i źródłowych. Jednym ze sposobów udostępniania jak największej ref struct ilości kodu jest utworzenie otoki wokół Utf8JsonReader i Newtonsoft.Json.JsonTextReader. Ta otoka zjednoczyłaby obszar powierzchni publicznej podczas izolowania różnic behawioralnych. Dzięki temu można odizolować zmiany głównie do konstrukcji typu wraz z przekazaniem nowego typu według odwołania. Jest to wzorzec, który jest zgodny z biblioteką Microsoft.Extensions.DependencyModel :

Utf8JsonWriter vs. JsonTextWriter

System.Text.Json.Utf8JsonWriter to wysokowydajny sposób pisania zakodowanego w formacie UTF-8 tekstu JSON z typowych typów platformy .NET, takich jak String, Int32i DateTime. Moduł zapisywania jest typem niskiego poziomu, który może służyć do tworzenia niestandardowych serializatorów.

Zapisywanie wartości pierwotnych

Newtonsoft.Json ma metodę WriteRawValue , która zapisuje nieprzetworzone dane JSON, w których oczekiwana jest wartość. System.Text.Json ma bezpośredni odpowiednik: Utf8JsonWriter.WriteRawValue. Aby uzyskać więcej informacji, zobacz Zapisywanie nieprzetworzonych danych JSON.

Dostosowywanie formatu JSON

JsonTextWriter zawiera następujące ustawienia, dla których Utf8JsonWriter nie ma odpowiednika:

  • QuoteChar — określa znak, który ma być używany do ujęć wartości ciągów. Utf8JsonWriter zawsze używa cudzysłowów podwójnych.
  • QuoteName — określa, czy należy otaczać nazwy właściwości cudzysłowami. Utf8JsonWriter zawsze otacza je cudzysłowami.

Począwszy od platformy .NET 9, można dostosować znak i rozmiar wcięcia, Utf8JsonWriter aby użyć opcji uwidocznionych przez JsonWriterOptions strukturę:

  • JsonWriterOptions.IndentCharacter
  • JsonWriterOptions.IndentSize

JsonTextWriter zawiera następujące ustawienia, dla których Utf8JsonWriter nie ma odpowiednika:

  • Wcięcie — określa liczbę znaków do wcięcia. Utf8JsonWriter zawsze wcięcie o 2 znaki.
  • IndentChar — określa znak, który ma być używany do wcięcia. Utf8JsonWriter zawsze używa białych znaków.
  • QuoteChar — określa znak, który ma być używany do ujęć wartości ciągów. Utf8JsonWriter zawsze używa cudzysłowów podwójnych.
  • QuoteName — określa, czy należy otaczać nazwy właściwości cudzysłowami. Utf8JsonWriter zawsze otacza je cudzysłowami.

Nie ma obejść, które umożliwiają dostosowanie kodu JSON utworzonego w Utf8JsonWriter ten sposób.

Zapisywanie wartości przedziału czasu, identyfikatora URI lub znaku

JsonTextWriter Udostępnia WriteValue metody wartości TimeSpan, Uri i char . Utf8JsonWriter nie ma równoważnych metod. Zamiast tego sformatuj te wartości jako ciągi (wywołując ToString()na przykład , i wywołaj metodę WriteStringValue.

Wiele obiektów docelowych do pisania kodu JSON

Jeśli musisz nadal korzystać Newtonsoft.Json z niektórych platform docelowych, możesz mieć wiele implementacji i mieć dwie implementacje. Nie jest to jednak proste i wymagałoby duplikowania niektórych #ifdefs i źródłowych. Jednym ze sposobów udostępniania jak największej ilości kodu jest utworzenie otoki wokół Utf8JsonWriter i Newtonsoft.Json.JsonTextWriter. Ta otoka zjednoczyłaby obszar powierzchni publicznej podczas izolowania różnic behawioralnych. Dzięki temu można odizolować zmiany głównie do konstrukcji typu. Biblioteka Microsoft.Extensions.DependencyModel jest następująca:

TypeNameHandling.All nie jest obsługiwany

Decyzja o wykluczeniu TypeNameHandling.Allfunkcji równoważnych z System.Text.Json funkcji była celowa. Zezwalanie ładunkowi JSON na określanie własnych informacji o typie jest typowym źródłem luk w zabezpieczeniach w aplikacjach internetowych. W szczególności skonfigurowanie za pomocą Newtonsoft.JsonTypeNameHandling.All polecenia umożliwia klientowi zdalnemu osadzanie całej aplikacji wykonywalnego w samym ładunku JSON, dzięki czemu podczas deserializacji aplikacja internetowa wyodrębnia i uruchamia osadzony kod. Aby uzyskać więcej informacji, zobacz piątek 13 ataków JSON w programie PowerPoint i piątek 13. szczegóły ataków JSON.

Zapytania ścieżki JSON nie są obsługiwane

Dom JsonDocument nie obsługuje wykonywania zapytań przy użyciu ścieżki JSON.

W modelu JsonNode DOM każde JsonNode wystąpienie ma metodę zwracającą GetPath ścieżkę do tego węzła. Nie ma jednak wbudowanego interfejsu API do obsługi zapytań opartych na ciągach zapytania ścieżki JSON.

Aby uzyskać więcej informacji, zobacz problem dotnet/runtime #31068 GitHub.

Niektóre limity nie można skonfigurować

System.Text.Json ustawia limity, których nie można zmienić dla niektórych wartości, takich jak maksymalny rozmiar tokenu w znakach (166 MB) i podstawowy 64 (125 MB). Aby uzyskać więcej informacji, zobacz JsonConstants w kodzie źródłowym i problemie z usługą GitHub dotnet/runtime #39953.

NaN, Infinity, -Infinity

Newtonsoft analizuje NaNtokeny ciągów , Infinityi -Infinity JSON. W programie System.Text.Jsonużyj polecenia JsonNumberHandling.AllowNamedFloatingPointLiterals. Aby uzyskać informacje na temat używania tego ustawienia, zobacz Zezwalanie na liczby w cudzysłowie lub zapisywanie ich.

Dodatkowe zasoby