diff --git a/docs/framework/wcf/feature-details/stand-alone-json-serialization.md b/docs/framework/wcf/feature-details/stand-alone-json-serialization.md index 36aac7ed7c0aa..8f122da82d697 100644 --- a/docs/framework/wcf/feature-details/stand-alone-json-serialization.md +++ b/docs/framework/wcf/feature-details/stand-alone-json-serialization.md @@ -6,7 +6,7 @@ ms.assetid: 312bd7b2-1300-4b12-801e-ebe742bd2287 # Stand-Alone JSON Serialization using DataContractJsonSerializer > [!NOTE] -> This article is about . For most scenarios that involve serializing and deserializing JSON, we recommend the tools in the [System.Text.Json namespace](../../../standard/serialization/system-text-json-overview.md). +> This article is about . For most scenarios that involve serializing and deserializing JSON, we recommend the APIs in the [System.Text.Json namespace](../../../standard/serialization/system-text-json-overview.md). JSON (JavaScript Object Notation) is a data format that is specifically designed to be used by JavaScript code running on Web pages inside the browser. It is the default data format used by ASP.NET AJAX services created in Windows Communication Foundation (WCF). diff --git a/docs/framework/wcf/samples/json-serialization.md b/docs/framework/wcf/samples/json-serialization.md index c889a7ec49aa1..9631a191e7c69 100644 --- a/docs/framework/wcf/samples/json-serialization.md +++ b/docs/framework/wcf/samples/json-serialization.md @@ -6,7 +6,7 @@ ms.assetid: 3c2c4747-7510-4bdf-b4fe-64f98428ef4a # DataContractJsonSerializer sample > [!NOTE] -> This sample is for . For most scenarios that involve serializing and deserializing JSON, we recommend the tools in the [System.Text.Json namespace](../../../standard/serialization/system-text-json-overview.md). +> This sample is for . For most scenarios that involve serializing and deserializing JSON, we recommend the APIs in the [System.Text.Json namespace](../../../standard/serialization/system-text-json-overview.md). supports the same types as . The JSON data format is especially useful when writing Asynchronous JavaScript and XML (AJAX)-style Web applications. AJAX support in Windows Communication Foundation (WCF) is optimized for use with ASP.NET AJAX through the ScriptManager control. For examples of how to use Windows Communication Foundation (WCF) with ASP.NET AJAX, see the [AJAX Samples](ajax.md). diff --git a/docs/standard/serialization/system-text-json-converters-how-to.md b/docs/standard/serialization/system-text-json-converters-how-to.md index 5b80d40013d66..a4e2b14fb5a27 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -1,6 +1,6 @@ --- title: "How to write custom converters for JSON serialization - .NET" -ms.date: "10/16/2019" +ms.date: "01/10/2020" helpviewer_keywords: - "JSON serialization" - "serializing objects" @@ -9,7 +9,7 @@ helpviewer_keywords: - "converters" --- -# How to write custom converters for JSON serialization in .NET +# How to write custom converters for JSON serialization (marshalling) in .NET This article shows how to create custom converters for the JSON serialization classes that are provided in the namespace. For an introduction to `System.Text.Json`, see [How to serialize and deserialize JSON in .NET](system-text-json-how-to.md). @@ -18,9 +18,9 @@ A *converter* is a class that converts an object or a value to and from JSON. Th * To override the default behavior of a built-in converter. For example, you might want `DateTime` values to be represented by mm/dd/yyyy format instead of the default ISO 8601-1:2019 format. * To support a custom value type. For example, a `PhoneNumber` struct. -You can also write custom converters to extend `System.Text.Json` with functionality not included in the current release. The following scenarios are covered later in this article: +You can also write custom converters to customize or extend `System.Text.Json` with functionality not included in the current release. The following scenarios are covered later in this article: -* [Deserialize inferred types to Object properties](#deserialize-inferred-types-to-object-properties). +* [Deserialize inferred types to object properties](#deserialize-inferred-types-to-object-properties). * [Support Dictionary with non-string key](#support-dictionary-with-non-string-key). * [Support polymorphic deserialization](#support-polymorphic-deserialization). @@ -63,9 +63,9 @@ The following steps explain how to create a converter by following the basic pat * Create a class that derives from where `T` is the type to be serialized and deserialized. * Override the `Read` method to deserialize the incoming JSON and convert it to type `T`. Use the that is passed to the method to read the JSON. * Override the `Write` method to serialize the incoming object of type `T`. Use the that is passed to the method to write the JSON. -* Override the `CanConvert` method only if necessary. The default implementation returns `true` when the type to convert is type `T`. Therefore, converters that support only type `T` don't need to override this method. For an example of a converter that does need to override this method, see the [polymorphic deserialization](#support-polymorphic-deserialization) section later in this article. +* Override the `CanConvert` method only if necessary. The default implementation returns `true` when the type to convert is of type `T`. Therefore, converters that support only type `T` don't need to override this method. For an example of a converter that does need to override this method, see the [polymorphic deserialization](#support-polymorphic-deserialization) section later in this article. -You can refer to the [built-in converters source code](https://github.com/dotnet/corefx/tree/master/src/System.Text.Json/src/System/Text/Json/Serialization/Converters/) as reference implementations for writing custom converters. +You can refer to the [built-in converters source code](https://github.com/dotnet/runtime/tree/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/) as reference implementations for writing custom converters. ## Steps to follow the factory pattern @@ -168,20 +168,21 @@ A built-in converter is chosen only if no applicable custom converter is registe The following sections provide converter samples that address some common scenarios that built-in functionality doesn't handle. -* [Deserialize inferred types to Object properties](#deserialize-inferred-types-to-object-properties) +* [Deserialize inferred types to object properties](#deserialize-inferred-types-to-object-properties) * [Support Dictionary with non-string key](#support-dictionary-with-non-string-key) * [Support polymorphic deserialization](#support-polymorphic-deserialization) -### Deserialize inferred types to Object properties +### Deserialize inferred types to object properties -When deserializing to a property of type `Object`, a `JsonElement` object is created. The reason is that the deserializer doesn't know what CLR type to create, and it doesn't try to guess. For example, if a JSON property has "true", the deserializer doesn't infer that the value is a `Boolean`, and if an element has "01/01/2019", the deserializer doesn't infer that it's a `DateTime`. +When deserializing to a property of type `object`, a `JsonElement` object is created. The reason is that the deserializer doesn't know what CLR type to create, and it doesn't try to guess. For example, if a JSON property has "true", the deserializer doesn't infer that the value is a `Boolean`, and if an element has "01/01/2019", the deserializer doesn't infer that it's a `DateTime`. Type inference can be inaccurate. If the deserializer parses a JSON number that has no decimal point as a `long`, that might result in out-of-range issues if the value was originally serialized as a `ulong` or `BigInteger`. Parsing a number that has a decimal point as a `double` might lose precision if the number was originally serialized as a `decimal`. -For scenarios that require type inference, the following code shows a custom converter for `Object` properties. The code converts: +For scenarios that require type inference, the following code shows a custom converter for `object` properties. The code converts: * `true` and `false` to `Boolean` -* Numbers to `long` or `double` +* Numbers without a decimal to `long` +* Numbers with a decimal to `double` * Dates to `DateTime` * Strings to `string` * Everything else to `JsonElement` @@ -190,9 +191,9 @@ For scenarios that require type inference, the following code shows a custom con The following code registers the converter: -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/ConvertInferredTypesToObject.cs?name=SnippetRegister)] +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/DeserializeInferredTypesToObject.cs?name=SnippetRegister)] -Here's an example type with `Object` properties: +Here's an example type with `object` properties: [!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecast.cs?name=SnippetWFWithObjectProperties)] @@ -208,7 +209,7 @@ The following example of JSON to deserialize contains values that will be deseri Without the custom converter, deserialization puts a `JsonElement` in each property. -The [unit tests folder](https://github.com/dotnet/corefx/blob/master/src/System.Text.Json/tests/Serialization/) in the `System.Text.Json.Serialization` namespace has more examples of custom converters that handle deserialization to Object properties. +The [unit tests folder](https://github.com/dotnet/runtime/blob/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/libraries/System.Text.Json/tests/Serialization/) in the `System.Text.Json.Serialization` namespace has more examples of custom converters that handle deserialization to `object` properties. ### Support Dictionary with non-string key @@ -220,7 +221,7 @@ The following code shows a custom converter that works with `Dictionary` converter that accepts external data -* `Long[]` converter that works with a comma-delimited list of numbers +The [unit tests folder](https://github.com/dotnet/runtime/blob/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/libraries/System.Text.Json/tests/Serialization/) in the `System.Text.Json.Serialization` source code includes other custom converter samples, such as: + +* [Int32 converter that converts null to 0 on deserialize](https://github.com/dotnet/runtime/blob/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.NullValueType.cs) +* [Int32 converter that allows both string and number values on deserialize](https://github.com/dotnet/runtime/blob/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Int32.cs) +* [Enum converter](https://github.com/dotnet/runtime/blob/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Enum.cs) +* [List\ converter that accepts external data](https://github.com/dotnet/runtime/blob/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.List.cs) +* [Long[] converter that works with a comma-delimited list of numbers](https://github.com/dotnet/runtime/blob/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Array.cs) + +If you need to make a converter that modifies the behavior of an existing built-in converter, you can get [the source code of the existing converter](https://github.com/dotnet/runtime/tree/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters) to serve as a starting point for customization. ## Additional resources +* [Source code for built-in converters](https://github.com/dotnet/runtime/tree/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters) +* [DateTime and DateTimeOffset support in System.Text.Json](../datetime/system-text-json-support.md) * [System.Text.Json overview](system-text-json-overview.md) -* [System.Text.Json API reference](xref:System.Text.Json) * [How to use System.Text.Json](system-text-json-how-to.md) -* [Source code for built-in converters](https://github.com/dotnet/corefx/tree/master/src/System.Text.Json/src/System/Text/Json/Serialization/Converters/) -* GitHub issues related to custom converters for `System.Text.Json` - * [36639 Introducing custom converters](https://github.com/dotnet/corefx/issues/36639) - * [38713 About deserializing to Object](https://github.com/dotnet/corefx/issues/38713) - * [40120 About non-string-key dictionaries](https://github.com/dotnet/corefx/issues/40120) - * [37787 About polymorphic deserialization](https://github.com/dotnet/corefx/issues/37787) +* [How to migrate from Newtonsoft.Json](system-text-json-migrate-from-newtonsoft-how-to.md) +* [System.Text.Json API reference](xref:System.Text.Json) +* [System.Text.Json.Serialization API reference](xref:System.Text.Json.Serialization) + diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index 4dce67a3eea5d..0c4f984d2c364 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -1,6 +1,6 @@ --- title: "How to serialize and deserialize JSON using C# - .NET" -ms.date: "09/16/2019" +ms.date: "01/10/2020" helpviewer_keywords: - "JSON serialization" - "serializing objects" @@ -8,7 +8,7 @@ helpviewer_keywords: - "objects, serializing" --- -# How to serialize and deserialize JSON in .NET +# How to serialize and deserialize (marshal and unmarshal) JSON in .NET This article shows how to use the namespace to serialize and deserialize to and from JavaScript Object Notation (JSON). @@ -104,7 +104,7 @@ Serializing to UTF-8 is about 5-10% faster than using the string-based methods. * The [default encoder](xref:System.Text.Encodings.Web.JavaScriptEncoder.Default) escapes non-ASCII characters, HTML-sensitive characters within the ASCII-range, and characters that must be escaped according to [the RFC 8259 JSON spec](https://tools.ietf.org/html/rfc8259#section-7). * By default, JSON is minified. You can [pretty-print the JSON](#serialize-to-formatted-json). * By default, casing of JSON names matches the .NET names. You can [customize JSON name casing](#customize-json-names-and-values). -* Circular references are detected and exceptions thrown. For more information, see [issue 38579 on circular references](https://github.com/dotnet/corefx/issues/38579) in the dotnet/corefx repository on GitHub. +* Circular references are detected and exceptions thrown. * Currently, fields are excluded. Supported types include: @@ -113,7 +113,7 @@ Supported types include: * User-defined [Plain Old CLR Objects (POCOs)](https://stackoverflow.com/questions/250001/poco-definition). * One-dimensional and jagged arrays (`ArrayName[][]`). * `Dictionary` where `TValue` is `object`, `JsonElement`, or a POCO. -* Collections from the following namespaces. For more information, see the [issue on collection support](https://github.com/dotnet/corefx/issues/36643) in the dotnet/corefx repository on GitHub. +* Collections from the following namespaces. * * * @@ -149,7 +149,7 @@ To deserialize from UTF-8, call a that lets you specify the type at runtime: @@ -487,16 +489,76 @@ To serialize the properties of the derived type, use one of the following approa In the preceding example scenario, both approaches cause the `WindSpeed` property to be included in the JSON output: +```json +{ + "WindSpeed": 35, + "Date": "2019-08-01T00:00:00-07:00", + "TemperatureCelsius": 25, + "Summary": "Hot" +} +``` + +> [!IMPORTANT] +> These approaches provide polymorphic serialization only for the root object to be serialized, not for properties of that root object. + +You can get polymorphic serialization for lower-level objects if you define them as type `object`. For example, suppose your `WeatherForecast` class has a property named `PreviousForecast` that can be defined as type `WeatherForecast` or `object`: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecast.cs?name=SnippetWFWithPrevious)] + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecast.cs?name=SnippetWFWithPreviousAsObject)] + +If the `PreviousForecast` property contains an instance of `WeatherForecastDerived`: + +* The JSON output from serializing `WeatherForecastWithPrevious` **doesn't include** `WindSpeed`. +* The JSON output from serializing `WeatherForecastWithPreviousAsObject` **includes** `WindSpeed`. + +To serialize `WeatherForecastWithPreviousAsObject`, it isn't necessary to call `Serialize` or `GetType` because the root object isn't the one that may be of a derived type. The following code example doesn't call `Serialize` or `GetType`: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/SerializePolymorphic.cs?name=SnippetSerializeSecondLevel)] + +The preceding code correctly serializes `WeatherForecastWithPreviousAsObject`: + ```json { "Date": "2019-08-01T00:00:00-07:00", "TemperatureCelsius": 25, "Summary": "Hot", - "WindSpeed": 35 + "PreviousForecast": { + "WindSpeed": 35, + "Date": "2019-08-01T00:00:00-07:00", + "TemperatureCelsius": 25, + "Summary": "Hot" + } } ``` -For information about polymorphic deserialization, see [Support polymorphic deserialization](system-text-json-converters-how-to.md#support-polymorphic-deserialization). +The same approach of defining properties as `object` works with interfaces. Suppose you have the following interface and implementation, and you want to serialize a class with properties that contain implementation instances: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/IForecast.cs)] + +When you serialize an instance of `Forecasts`, only `Tuesday` shows the `WindSpeed` property, because `Tuesday` is defined as `object`: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/SerializePolymorphic.cs?name=SnippetSerializeInterface)] + +The following example shows the JSON that results from the preceding code: + +```json +{ + "Monday": { + "Date": "2020-01-06T00:00:00-08:00", + "TemperatureCelsius": 10, + "Summary": "Cool" + }, + "Tuesday": { + "Date": "2020-01-07T00:00:00-08:00", + "TemperatureCelsius": 11, + "Summary": "Rainy", + "WindSpeed": 10 + } +} +``` + +For more information about polymorphic **serialization**, and for information about **deserialization**, see [How to migrate from Newtonsoft.Json to System.Text.Json](system-text-json-migrate-from-newtonsoft-how-to.md#polymorphic-serialization). ## Allow comments and trailing commas @@ -621,11 +683,11 @@ To change this behavior, set is a high-performance, low allocation, forward-only reader for UTF-8 encoded JSON text, read from a `ReadOnlySpan`. The `Utf8JsonReader` is a low-level type that can be used to build custom parsers and deserializers. The method uses `Utf8JsonReader` under the covers. + is a high-performance, low allocation, forward-only reader for UTF-8 encoded JSON text, read from a `ReadOnlySpan` or `ReadOnlySequence`. The `Utf8JsonReader` is a low-level type that can be used to build custom parsers and deserializers. The method uses `Utf8JsonReader` under the covers. is a high-performance way to write UTF-8 encoded JSON text from common .NET types like `String`, `Int32`, and `DateTime`. The writer is a low-level type that can be used to build custom serializers. The method uses `Utf8JsonWriter` under the covers. @@ -694,14 +756,15 @@ The following example shows how to read a file synchronously and search for a va The preceding code: +* Assumes the JSON contains an array of objects and each object may contain a "name" property of type string. +* Counts objects and "name" property values that end with "University". * Assumes the file is encoded as UTF-16 and transcodes it into UTF-8. A file encoded as UTF-8 can be read directly into a `ReadOnlySpan`, by using the following code: ```csharp ReadOnlySpan jsonReadOnlySpan = File.ReadAllBytes(fileName); ``` -* Assumes the JSON contains an array of objects and each object may contain a "name" property of type string. -* Counts objects and `name` property values that end with "University". + If the file contains a UTF-8 byte order mark (BOM), remove it before passing the bytes to the `Utf8JsonReader`, since the reader expects text. Otherwise, the BOM is considered invalid JSON, and the reader throws an exception. Here's a JSON sample that the preceding code can read. The resulting summary message is "2 out of 4 have names that end with 'University'": @@ -710,7 +773,8 @@ Here's a JSON sample that the preceding code can read. The resulting summary mes ## Additional resources * [System.Text.Json overview](system-text-json-overview.md) -* [System.Text.Json API reference](xref:System.Text.Json) -* [Write custom converters for System.Text.Json](system-text-json-converters-how-to.md) +* [How to write custom converters](system-text-json-converters-how-to.md) +* [How to migrate from Newtonsoft.Json](system-text-json-migrate-from-newtonsoft-how-to.md) * [DateTime and DateTimeOffset support in System.Text.Json](../datetime/system-text-json-support.md) -* [GitHub issues in the dotnet/corefx repository labeled json-functionality-doc](https://github.com/dotnet/corefx/labels/json-functionality-doc) +* [System.Text.Json API reference](xref:System.Text.Json) + diff --git a/docs/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to.md b/docs/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to.md new file mode 100644 index 0000000000000..520f01c74f6d4 --- /dev/null +++ b/docs/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to.md @@ -0,0 +1,617 @@ +--- +title: "Migrate from Newtonsoft.Json to System.Text.Json - .NET" +author: tdykstra +ms.author: tdykstra +ms.date: "01/10/2020" +helpviewer_keywords: + - "JSON serialization" + - "serializing objects" + - "serialization" + - "objects, serializing" +--- + +# How to migrate from Newtonsoft.Json to System.Text.Json + +This article shows how to migrate from [Newtonsoft.Json](https://www.newtonsoft.com/json) to . + + `System.Text.Json` focuses primarily on performance, security, and standards compliance. It has some key differences in default behavior and doesn't aim to have feature parity with `Newtonsoft.Json`. For some scenarios, `System.Text.Json` has no built-in functionality, but there are recommended workarounds. For other scenarios, workarounds are impractical. If your application depends on a missing feature, consider [filing an issue](https://github.com/dotnet/runtime/issues/new) to find out if support for your scenario can be added. + + + +Most of this article is about how to use the API, but it also includes guidance on how to use the (which represents the Document Object Model or DOM), , and types. The article is organized into sections in the following order: + +* [Differences in **default** JsonSerializer behavior compared to Newtonsoft.Json](#differences-in-default-jsonserializer-behavior-compared-to-newtonsoftjson) +* [Scenarios using JsonSerializer that require workarounds](#scenarios-using-jsonserializer-that-require-workarounds) +* [Scenarios that JsonSerializer currently doesn't support](#scenarios-that-jsonserializer-currently-doesnt-support) +* [JsonDocument and JsonElement compared to JToken (like JObject, JArray)](#jsondocument-and-jsonelement-compared-to-jtoken-like-jobject-jarray) +* [Utf8JsonReader compared to JsonTextReader](#utf8jsonreader-compared-to-jsontextreader) +* [Utf8JsonWriter compared to JsonTextWriter](#utf8jsonwriter-compared-to-jsontextwriter) + +## Differences in default JsonSerializer behavior compared to Newtonsoft.Json + + is strict by default and avoids any guessing or interpretation on the caller's behalf, emphasizing deterministic behavior. The library is intentionally designed this way for performance and security. `Newtonsoft.Json` is flexible by default. This fundamental difference in design is behind many of the following specific differences in default behavior. + +### Case-insensitive deserialization + +During deserialization, `Newtonsoft.Json` does case-insensitive property name matching by default. The default is case-sensitive, which gives better performance since it's doing an exact match. For information about how to do case-insensitive matching, see [Case-insensitive property matching](system-text-json-how-to.md#case-insensitive-property-matching). + +If you're using `System.Text.Json` indirectly by using ASP.NET Core, you don't need to do anything to get behavior like `Newtonsoft.Json`. ASP.NET Core specifies the settings for [camel-casing property names](system-text-json-how-to.md#use-camel-case-for-all-json-property-names) and case-insensitive matching when it uses `System.Text.Json`. + +### Comments + +During deserialization, `Newtonsoft.Json` ignores comments in the JSON by default. The default is to throw exceptions for comments because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't include them. For information about how to allow comments, see [Allow comments and trailing commas](system-text-json-how-to.md#allow-comments-and-trailing-commas). + +### Trailing commas + +During deserialization, `Newtonsoft.Json` ignores trailing commas by default. It also ignores multiple trailing commas (for example, `[{"Color":"Red"},{"Color":"Green"},,]`). The default is to throw exceptions for trailing commas because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't allow them. For information about how to make `System.Text.Json` accept them, see [Allow comments and trailing commas](system-text-json-how-to.md#allow-comments-and-trailing-commas). There's no way to allow multiple trailing commas. + +### JSON strings (property names and string values) + +During deserialization, `Newtonsoft.Json` accepts property names surrounded by double quotes, single quotes, or without quotes. It accepts string values surrounded by double quotes or single quotes. For example, `Newtonsoft.Json` accepts the following JSON: + +```json +{ + "name1": "value", + 'name2': "value", + name3: 'value' +} +``` + +`System.Text.Json` only accepts property names and string values in double quotes because that format is required by the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification and is the only format considered valid JSON. + +A value enclosed in single quotes results in a [JsonException](xref:System.Text.Json.JsonException) with the following message: + +``` +''' is an invalid start of a value. +``` + +### Non-string values for string properties + +`Newtonsoft.Json` accepts non-string values, such as a number or the literals `true` and `false`, for deserialization to properties of type string. Here's an example of JSON that `Newtonsoft.Json` successfully deserializes to the following class: + +```json +{ + "String1": 1, + "String2": true, + "String3": false +} +``` + +```csharp +public class ExampleClass +{ + public string String1 { get; set; } + public string String2 { get; set; } + public string String3 { get; set; } +} +``` + +`System.Text.Json` doesn't deserialize non-string values into string properties. A non-string value received for a string field results in a [JsonException](xref:System.Text.Json.JsonException) with the following message: + +``` +The JSON value could not be converted to System.String. +``` + +### Converter registration precedence + +The `Newtonsoft.Json` registration precedence for custom converters is as follows: + +* Attribute on property +* Attribute on type +* [Converters](https://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_JsonSerializerSettings_Converters.htm) collection + +This order means that a custom converter in the `Converters` collection is overridden by a converter that is registered by applying an attribute at the type level. Both of those registrations are overridden by an attribute at the property level. + +The registration precedence for custom converters is different: + +* Attribute on property +* collection +* Attribute on type + +The difference here is that a custom converter in the `Converters` collection overrides an attribute at the type level. The intention behind this order of precedence is to make run-time changes override design-time choices. There's no way to change the precedence. + +For more information about custom converter registration, see [Register a custom converter](system-text-json-converters-how-to.md#register-a-custom-converter). + +### Character escaping + +During serialization, `Newtonsoft.Json` is relatively permissive about letting characters through without escaping them. That is, it doesn't replace them with `\uxxxx` where `xxxx` is the character's code point. Where it does escape them, it does so by emitting a `\` before the character (for example, `"` becomes `\"`). escapes more characters by default to provide defense-in-depth protections against cross-site scripting (XSS) or information-disclosure attacks and does so by using the six-character sequence. `System.Text.Json` escapes all non-ASCII characters by default, so you don't need to do anything if you're using `StringEscapeHandling.EscapeNonAscii` in `Newtonsoft.Json`. `System.Text.Json` also escapes HTML-sensitive characters, by default. For information about how to override the default `System.Text.Json` behavior, see [Customize character encoding](system-text-json-how-to.md#customize-character-encoding). + +### Deserialization of object properties + +When `Newtonsoft.Json` deserializes to `object` properties in POCOs or in dictionaries of type `Dictionary`, it: + +* Infers the type of primitive values in the JSON payload (other than `null`) and returns the stored `string`, `long`, `double`, `boolean`, or `DateTime` as a boxed object. *Primitive values* are single JSON values such as a JSON number, string, `true`, `false`, or `null`. +* Returns a `JObject` or `JArray` for complex values in the JSON payload. *Complex values* are collections of JSON key-value pairs within braces (`{}`) or lists of values within brackets (`[]`). The properties and values within the braces or brackets can have additional properties or values. +* Returns a null reference when the payload has the `null` JSON literal. + + stores a boxed `JsonElement` for both primitive and complex values within the `System.Object` property or dictionary value. However, it treats `null` the same as `Newtonsoft.Json` and returns a null reference when the payload has the `null` JSON literal in it. + +To implement type inference for `object` properties, create a converter like the example in [How to write custom converters](system-text-json-converters-how-to.md#deserialize-inferred-types-to-object-properties). + +### Maximum depth + +`Newtonsoft.Json` doesn't have a maximum depth limit by default. For there's a default limit of 64, and it's configurable by setting . + +### Stack type handling + +In , the order of a stack's contents is reversed when it's serialized. This behavior applies to the following types and interface and user-defined types that derive from them: + +* +* +* +* + +A custom converter could be implemented to keep stack contents in the same order. + +### Omit null-value properties + +`Newtonsoft.Json` has a global setting that causes null-value properties to be excluded from serialization: [NullValueHandling.Ignore](https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_NullValueHandling.htm). The corresponding option in is . + +## Scenarios using JsonSerializer that require workarounds + +The following scenarios aren't supported by built-in functionality, but sample code is provided for workarounds. Most of the workarounds require that you implement [custom converters](system-text-json-converters-how-to.md). + +### Specify date format + +`Newtonsoft.Json` provides several ways to control how properties of `DateTime` and `DateTimeOffset` types are serialized and deserialized: + +* The `DateTimeZoneHandling` setting can be used to serialize all `DateTime` values as UTC dates. +* The `DateFormatString` setting and `DateTime` converters can be used to customize the format of date strings. + +In , the only format that has built-in support is ISO 8601-1:2019 since it's widely adopted, unambiguous, and makes round trips precisely. To use any other format, create a custom converter. For more information, see [DateTime and DateTimeOffset support in System.Text.Json](../datetime/system-text-json-support.md). + +### Quoted numbers + +`Newtonsoft.Json` can serialize or deserialize numbers represented by JSON strings (surrounded by quotes). For example, it can accept: `{"DegreesCelsius":"23"}` instead of `{"DegreesCelsius":23}`. To enable that behavior in , implement a custom converter like the following example. The converter handles properties defined as `long`: + +* It serializes them as JSON strings. +* It accepts JSON numbers and numbers within quotes while deserializing. + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/LongToStringConverter.cs)] + +Register this custom converter by [using an attribute](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-property) on individual `long` properties or by [adding the converter](system-text-json-converters-how-to.md#registration-sample---converters-collection) to the collection. + +### Dictionary with non-string key + +`Newtonsoft.Json` supports collections of type `Dictionary`. The built-in support for dictionary collections in is limited to `Dictionary`. That is, the key must be a string. + +To support a dictionary with an integer or some other type as the key, create a converter like the example in [How to write custom converters](system-text-json-converters-how-to.md#support-dictionary-with-non-string-key). + +### Polymorphic serialization + +`Newtonsoft.Json` automatically does polymorphic serialization. For information about the limited polymorphic serialization capabilities of , see [Serialize properties of derived classes](system-text-json-how-to.md#serialize-properties-of-derived-classes). + +The workaround described there is to define properties that may contain derived classes as type `object`. If that isn't possible, another option is to create a converter with a `Write` method for the whole inheritance type hierarchy like the example in [How to write custom converters](system-text-json-converters-how-to.md#support-polymorphic-deserialization). + +### Polymorphic deserialization + +`Newtonsoft.Json` has a `TypeNameHandling` setting that adds type name metadata to the JSON while serializing. It uses the metadata while deserializing to do polymorphic deserialization. can do a limited range of [polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes) but not polymorphic deserialization. + +To support polymorphic deserialization, create a converter like the example in [How to write custom converters](system-text-json-converters-how-to.md#support-polymorphic-deserialization). + +### Required properties + +During deserialization, doesn't throw an exception if no value is received in the JSON for one of the properties of the target type. For example, if you have a `WeatherForecast` class: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecast.cs?name=SnippetWF)] + +The following JSON is deserialized without error: + +```json +{ + "TemperatureCelsius": 25, + "Summary": "Hot" +} +``` + +To make deserialization fail if no `Date` property is in the JSON, implement a custom converter. The following sample converter code throws an exception if the `Date` property isn't set after deserialization is complete: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecastRequiredPropertyConverter.cs)] + +Register this custom converter by [using an attribute on the POCO class](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-type) or by [adding the converter](system-text-json-converters-how-to.md#registration-sample---converters-collection) to the collection. + +If you follow this pattern, don't pass in the options object when recursively calling or . The options object contains the collection. If you pass it in to `Serialize` or `Deserialize`, the custom converter calls into itself, making an infinite loop that results in a stack overflow exception. If the default options are not feasible, create a new instance of the options with the settings that you need. This approach will be slow since each new instance caches independently. + +The preceding converter code is a simplified example. Additional logic would be required if you need to handle attributes (such as [[JsonIgnore]](xref:System.Text.Json.Serialization.JsonIgnoreAttribute) or different options (such as custom encoders). Also, the example code doesn't handle properties for which a default value is set in the constructor. And this approach doesn't differentiate between the following scenarios: + +* A property is missing from the JSON. +* A property for a non-nullable type is present in the JSON, but the value is the default for the type, such as zero for an `int`. +* A property for a nullable type is present in the JSON, but the value is null. + +### Deserialize null to non-nullable type + +`Newtonsoft.Json` doesn't throw an exception in the following scenario: + +* `NullValueHandling` is set to `Ignore`, and +* During deserialization, the JSON contains a null value for a non-nullable type. + +In the same scenario, does throw an exception. (The corresponding null handling setting is .) + +If you own the target type, the best workaround is to make the property in question nullable (for example, change `int` to `int?`). + +Another workaround is to make a converter for the type, such as the following example that handles null values for `DateTimeOffset` types: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/DateTimeOffsetNullHandlingConverter.cs)] + +Register this custom converter by [using an attribute on the property](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-property) or by [adding the converter](system-text-json-converters-how-to.md#registration-sample---converters-collection) to the collection. + +**Note:** The preceding converter **handles null values differently** than `Newtonsoft.Json` does for POCOs that specify default values. For example, suppose the following code represents your target object: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecast.cs?name=SnippetWFWithDefault)] + +And suppose the following JSON is deserialized by using the preceding converter: + +```json +{ + "Date": null, + "TemperatureCelsius": 25, + "Summary": null +} +``` + +After deserialization, the `Date` property has 1/1/0001 (`default(DateTimeOffset)`), that is, the value set in the constructor is overwritten. Given the same POCO and JSON, `Newtonsoft.Json` deserialization would leave 1/1/2001 in the `Date` property. + +### Deserialize to immutable classes and structs + +`Newtonsoft.Json` can deserialize to immutable classes and structs because it can use constructors that have parameters. supports only public parameterless constructors. As a workaround, you can call a constructor with parameters in a custom converter. + +Here's an immutable struct with multiple constructor parameters: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/ImmutablePoint.cs#ImmutablePoint)] + +And here's a converter that serializes and deserializes this struct: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/ImmutablePointConverter.cs)] + +Register this custom converter by [adding the converter](system-text-json-converters-how-to.md#registration-sample---converters-collection) to the collection. + +For an example of a similar converter that handles open generic properties, see the [built-in converter for key-value pairs](https://github.com/dotnet/runtime/blob/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterKeyValuePair.cs). + +### Specify constructor to use + +The `Newtonsoft.Json` `[JsonConstructor]` attribute lets you specify which constructor to call when deserializing to a POCO. supports only parameterless constructors. As a workaround, you can call whichever constructor you need in a custom converter. See the example for [Deserialize to immutable classes and structs](#deserialize-to-immutable-classes-and-structs). + +### Conditionally ignore a property + +`Newtonsoft.Json` has several ways to conditionally ignore a property on serialization or deserialization: + +* `DefaultContractResolver` lets you select properties to include or exclude, based on arbitrary criteria. +* The `NullValueHandling` and `DefaultValueHandling` settings on `JsonSerializerSettings` let you specify that all null-value or default-value properties should be ignored. +* The `NullValueHandling` and `DefaultValueHandling` settings on the `[JsonProperty]` attribute let you specify individual properties that should be ignored when set to null or the default value. + + provides the following ways to omit properties while serializing: + +* The [[JsonIgnore]](system-text-json-how-to.md#exclude-individual-properties) attribute on a property causes the property to be omitted from the JSON during serialization. +* The [IgnoreNullValues](system-text-json-how-to.md#exclude-all-null-value-properties) global option lets you exclude all null-value properties. +* The [IgnoreReadOnlyProperties](system-text-json-how-to.md#exclude-all-read-only-properties) global option lets you exclude all read-only properties. + +These options **don't** let you: + +* Ignore all properties that have the default value for the type. +* Ignore selected properties that have the default value for the type. +* Ignore selected properties if their value is null. +* Ignore selected properties based on arbitrary criteria evaluated at run time. + +For that functionality, you can write a custom converter. Here's a sample POCO and a custom converter for it that illustrates this approach: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecast.cs?name=SnippetWF)] + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecastRuntimeIgnoreConverter.cs)] + +The converter causes the `Summary` property to be omitted from serialization if its value is null, an empty string, or "N/A". + +Register this custom converter by [using an attribute on the class](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-type) or by [adding the converter](system-text-json-converters-how-to.md#registration-sample---converters-collection) to the collection. + +This approach requires additional logic if: + +* The POCO includes complex properties. +* You need to handle attributes such as `[JsonIgnore]` or options such as custom encoders. + +### Callbacks + +`Newtonsoft.Json` lets you execute custom code at several points in the serialization or deserialization process: + +* OnDeserializing (when beginning to deserialize an object) +* OnDeserialized (when finished deserializing an object) +* OnSerializing (when beginning to serialize an object) +* OnSerialized (when finished serializing an object) + +In , you can simulate callbacks by writing a custom converter. The following example shows a custom converter for a POCO. The converter includes code that displays a message at each point that corresponds to a `Newtonsoft.Json` callback. + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecastCallbacksConverter.cs)] + +Register this custom converter by [using an attribute on the class](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-type) or by [adding the converter](system-text-json-converters-how-to.md#registration-sample---converters-collection) to the collection. + +If you use a custom converter that follows the preceding sample: + +* The `OnDeserializing` code doesn't have access to the new POCO instance. To manipulate the new POCO instance at the start of deserialization, put that code in the POCO constructor. +* Don't pass in the options object when recursively calling `Serialize` or `Deserialize`. The options object contains the `Converters` collection. If you pass it in to `Serialize` or `Deserialize`, the converter will be used, making an infinite loop that results in a stack overflow exception. + +## Scenarios that JsonSerializer currently doesn't support + +Workarounds are possible for the following scenarios, but some of them would be relatively difficult to implement. This article doesn't provide code samples for workarounds for these scenarios. + +This is not an exhaustive list of `Newtonsoft.Json` features that have no equivalents in `System.Text.Json`. The list includes many of the scenarios that have been requested in [GitHub issues](https://github.com/dotnet/runtime/issues?q=is%3Aopen+is%3Aissue+label%3Aarea-System.Text.Json) or [StackOverflow](https://stackoverflow.com/questions/tagged/system.text.json) posts. + +If you implement a workaround for one of these scenarios and can share the code, select the "**This page**" button at the bottom of the page. That creates a GitHub issue and adds it to the issues that are listed at the bottom of the page. + +### Types without built-in support + + doesn't provide built-in support for the following types: + +* and related types +* F# types, such as [discriminated unions](../../fsharp/language-reference/discriminated-unions.md), [record types](../../fsharp/language-reference/records.md), and [anonymous record types](../../fsharp/language-reference/anonymous-records.md). +* Collection types in the namespace +* +* +* +* +* +* +* and its associated generic types + +Custom converters can be implemented for types that don't have built-in support. + +### Public and non-public fields + +`Newtonsoft.Json` can serialize and deserialize fields as well as properties. only works with public properties. Custom converters can provide this functionality. + +### Internal and private property setters and getters + +`Newtonsoft.Json` can use private and internal property setters and getters via the `JsonProperty` attribute. supports only public setters. Custom converters can provide this functionality. + +### Preserve object references and handle loops + +By default, `Newtonsoft.Json` serializes by value. For example, if an object contains two properties that contain a reference to the same `Person` object, the values of that `Person` object's properties are duplicated in the JSON. + +`Newtonsoft.Json` has a `PreserveReferencesHandling` setting on `JsonSerializerSettings` that lets you serialize by reference: + +* An identifier metadata is added to the JSON created for the first `Person` object. +* The JSON that is created for the second `Person` object contains a reference to that identifier instead of property values. + +`Newtonsoft.Json` also has a `ReferenceLoopHandling` setting that lets you ignore circular references rather than throw an exception. + + only supports serialization by value and throws an exception for circular references. + +### System.Runtime.Serialization attributes + + doesn't support attributes from the `System.Runtime.Serialization` namespace, such as `DataMemberAttribute` and `IgnoreDataMemberAttribute`. + +### Octal numbers + +`Newtonsoft.Json` treats numbers with a leading zero as octal numbers. doesn't allow leading zeroes because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't allow them. + +### Populate existing objects + +The `JsonConvert.PopulateObject` method in `Newtonsoft.Json` deserializes a JSON document to an existing instance of a class, instead of creating a new instance. always creates a new instance of the target type by using the default public parameterless constructor. Custom converters can deserialize to an existing instance. + +### Reuse rather than replace properties + +The `Newtonsoft.Json` `ObjectCreationHandling` setting lets you specify that objects in properties should be reused rather than replaced during deserialization. always replaces objects in properties. Custom converters can provide this functionality. + +### Add to collections without setters + +During deserialization, `Newtonsoft.Json` adds objects to a collection even if the property has no setter. ignores properties that don't have setters. Custom converters can provide this functionality. + +### MissingMemberHandling + +`Newtonsoft.Json` can be configured to throw exceptions during deserialization if the JSON includes properties that are missing in the target type. ignores extra properties in the JSON, except when you use the [[JsonExtensionData] attribute](system-text-json-how-to.md#handle-overflow-json). There's no workaround for the missing member feature. + +### TraceWriter + +`Newtonsoft.Json` lets you debug by using a `TraceWriter` to view logs that are generated by serialization or deserialization. doesn't do logging. + +## JsonDocument and JsonElement compared to JToken (like JObject, JArray) + + provides the ability to parse and build a **read-only** Document Object Model (DOM) from existing JSON payloads. The DOM provides random access to data in a JSON payload. The JSON elements that compose the payload can be accessed via the type. The `JsonElement` type provides APIs to convert JSON text to common .NET types. `JsonDocument` exposes a property. + +### JsonDocument is IDisposable + +`JsonDocument` builds an in-memory view of the data into a pooled buffer. Therefore, unlike `JObject` or `JArray` from `Newtonsoft.Json`, the `JsonDocument` type implements `IDisposable` and needs to be used inside a using block. + +Only return a `JsonDocument` from your API if you want to transfer lifetime ownership and dispose responsibility to the caller. In most scenarios, that isn't necessary. If the caller needs to work with the entire JSON document, return the of the , which is a . If the caller needs to work with a particular element within the JSON document, return the of that . If you return the `RootElement` or a sub-element directly without making a `Clone`, the caller won't be able to access the returned `JsonElement` after the `JsonDocument` that owns it is disposed. + +Here's an example that requires you to make a `Clone`: + +```csharp +public JsonElement LookAndLoad(JsonElement source) +{ + string json = File.ReadAllText(source.GetProperty("fileName").GetString()); + + using (JsonDocument doc = JsonDocument.Parse(json)) + { + return doc.RootElement.Clone(); + } +} +``` + +The preceding code expects a `JsonElement` that contains a `fileName` property. It opens the JSON file and creates a `JsonDocument`. The method assumes that the caller wants to work with the entire document, so it returns the `Clone` of the `RootElement`. + +If you receive a `JsonElement` and are returning a sub-element, it's not necessary to return a `Clone` of the sub-element. The caller is responsible for keeping alive the `JsonDocument` that the passed-in `JsonElement` belongs to. For example: + +```csharp +public JsonElement ReturnFileName(JsonElement source) +{ + return source.GetProperty("fileName"); +} +``` + +### JsonDocument is read-only + +The DOM can't add, remove, or modify JSON elements. It's designed this way for performance and to reduce allocations for parsing common JSON payload sizes (that is, < 1 MB). If your scenario currently uses a modifiable DOM, one of the following workarounds might be feasible: + +* To build a `JsonDocument` from scratch (that is, without passing in an existing JSON payload to the `Parse` method), write the JSON text by using the `Utf8JsonWriter` and parse the output from that to make a new `JsonDocument`. +* To modify an existing `JsonDocument`, use it to write JSON text, making changes while you write, and parse the output from that to make a new `JsonDocument`. +* To merge existing JSON documents, equivalent to the `JObject.Merge` or `JContainer.Merge` APIs from `Newtonsoft.Json`, see [this GitHub issue](https://github.com/dotnet/corefx/issues/42466#issuecomment-570475853). + +### JsonElement is a union struct + +`JsonDocument` exposes the `RootElement` as a property of type , which is a union, struct type that encompasses any JSON element. `Newtonsoft.Json` uses dedicated hierarchical types like `JObject`,`JArray`, `JToken`, and so forth. `JsonElement` is what you can search and enumerate over, and you can use `JsonElement` to materialize JSON elements into .NET types. + +### How to search a JsonDocument and JsonElement for sub-elements + +Searches for JSON tokens using `JObject` or `JArray` from `Newtonsoft.Json` tend to be relatively fast because they're lookups in some dictionary. By comparison, searches on `JsonElement` require a sequential search of the properties and hence is relatively slow (for example when using `TryGetProperty`). is designed to minimize initial parse time rather than lookup time. Therefore, use the following approaches to optimize performance when searching through a `JsonDocument` object: + +* Use the built-in enumerators ( and ) rather than doing your own indexing or loops. +* Don't do a sequential search on the whole `JsonDocument` through every property by using `RootElement`. Instead, search on nested JSON objects based on the known structure of the JSON data. For example, if you're looking for a `Grade` property in `Student` objects, loop through the `Student` objects and get the value of `Grade` for each, rather than searching through all `JsonElement` objects looking for `Grade` properties. Doing the latter will result in unnecessary passes over the same data. + +For a code example, see [Use JsonDocument for access to data](system-text-json-how-to.md#use-jsondocument-for-access-to-data). + +## Utf8JsonReader compared to JsonTextReader + + is a high-performance, low allocation, forward-only reader for UTF-8 encoded JSON text, read from a [ReadOnlySpan\](xref:System.ReadOnlySpan%601) or [ReadOnlySequence\](xref:System.Buffers.ReadOnlySequence%601). The `Utf8JsonReader` is a low-level type that can be used to build custom parsers and deserializers. + +The following sections explain recommended programming patterns for using `Utf8JsonReader`. + +### Utf8JsonReader is a ref struct + +Because the `Utf8JsonReader` type is a *ref struct*, it has [certain limitations](../../csharp/language-reference/keywords/ref.md#ref-struct-types). For example, it can't be stored as a field on a class or struct other than a ref struct. To achieve high performance, this type must be a `ref struct` since it needs to cache the input [ReadOnlySpan\](xref:System.ReadOnlySpan%601), which itself is a ref struct. In addition, this type is mutable since it holds state. Therefore, **pass it by ref** rather than by value. Passing it by value would result in a struct copy and the state changes would not be visible to the caller. This differs from `Newtonsoft.Json` since the `Newtonsoft.Json` `JsonTextReader` is a class. For more information about how to use ref structs, see [Write safe and efficient C# code](../../csharp/write-safe-efficient-code.md). + +### Read UTF-8 text + +To achieve the best possible performance while using the `Utf8JsonReader`, read JSON payloads already encoded as UTF-8 text rather than as UTF-16 strings. For a code example, see [Filter data using Utf8JsonReader](system-text-json-how-to.md#filter-data-using-utf8jsonreader). + +### Read with a Stream or PipeReader + +The `Utf8JsonReader` supports reading from a UTF-8 encoded [ReadOnlySpan\](xref:System.ReadOnlySpan%601) or [ReadOnlySequence\](xref:System.Buffers.ReadOnlySequence%601) (which is the result of reading from a ). + +For synchronous reading, you could read the JSON payload until the end of the stream into a byte array and pass that into the reader. For reading from a string (which is encoded as UTF-16), call . to first transcode the string to a UTF-8 encoded byte array. Then pass that to the `Utf8JsonReader`. + +Since the `Utf8JsonReader` considers the input to be JSON text, a UTF-8 byte order mark (BOM) is considered invalid JSON. The caller needs to filter that out before passing the data to the reader. + +For code examples, see [Use Utf8JsonReader](system-text-json-how-to.md#use-utf8jsonreader). + +### Read with multi-segment ReadOnlySequence + +If your JSON input is a [ReadOnlySpan\](xref:System.ReadOnlySpan%601), each JSON element can be accessed from the `ValueSpan` property on the reader as you go through the read loop. However, if your input is a [ReadOnlySequence\](xref:System.Buffers.ReadOnlySequence%601) (which is the result of reading from a ), some JSON elements might straddle multiple segments of the `ReadOnlySequence` object. These elements would not be accessible from in a contiguous memory block. Instead, whenever you have a multi-segment `ReadOnlySequence` as input, poll the property on the reader to figure out how to access the current JSON element. Here's a recommended pattern: + +```csharp +while (reader.Read()) +{ + switch (reader.TokenType) + { + // ... + ReadOnlySpan jsonElement = reader.HasValueSequence ? + reader.ValueSequence.ToArray() : + reader.ValueSpan; + // ... + } +} +``` + +### Use ValueTextEquals for property name lookups + +Don't use to do byte-by-byte comparisons by calling for property name lookups. Call instead, because that method unescapes any characters that are escaped in the JSON. Here's an example that shows how to search for a property that is named "name": + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/ValueTextEqualsExample.cs?name=SnippetDefineUtf8Var)] + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/ValueTextEqualsExample.cs?name=SnippetUseUtf8Var&highlight=11)] + +### Read null values into nullable value types + +`Newtonsoft.Json` provides APIs that return , such as `ReadAsBoolean`, which handles a `Null` `TokenType` for you by returning a `bool?`. The built-in `System.Text.Json` APIs return only non-nullable value types. For example, returns a `bool`. It throws an exception if it finds `Null` in the JSON. The following examples show two ways to handle nulls, one by returning a nullable value type and one by returning the default value: + +```csharp +public bool? ReadAsNullableBoolean() +{ + _reader.Read(); + if (_reader.TokenType == JsonTokenType.Null) + { + return null; + } + if (_reader.TokenType != JsonTokenType.True && _reader.TokenType != JsonTokenType.False) + { + throw new JsonException(); + } + return _reader.GetBoolean(); +} +``` + +```csharp +public bool ReadAsBoolean(bool defaultValue) +{ + _reader.Read(); + if (_reader.TokenType == JsonTokenType.Null) + { + return defaultValue; + } + if (_reader.TokenType != JsonTokenType.True && _reader.TokenType != JsonTokenType.False) + { + throw new JsonException(); + } + return _reader.GetBoolean(); +} +``` + +### Multi-targeting + +If you need to continue to use `Newtonsoft.Json` for certain target frameworks, you can multi-target and have two implementations. However, this is not trivial and would require some `#ifdefs` and source duplication. One way to share as much code as possible is to create a `ref struct` wrapper around `Utf8JsonReader` and `Newtonsoft.Json` `JsonTextReader`. This wrapper would unify the public surface area while isolating the behavioral differences. This lets you isolate the changes mainly to the construction of the type, along with passing the new type around by reference. This is the pattern that the [Microsoft.Extensions.DependencyModel](https://www.nuget.org/packages/Microsoft.Extensions.DependencyModel/3.1.0/) library follows: + +* [UnifiedJsonReader.JsonTextReader.cs](https://github.com/dotnet/runtime/blob/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/installer/managed/Microsoft.Extensions.DependencyModel/UnifiedJsonReader.JsonTextReader.cs) +* [UnifiedJsonReader.Utf8JsonReader.cs](https://github.com/dotnet/runtime/blob/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/installer/managed/Microsoft.Extensions.DependencyModel/UnifiedJsonReader.Utf8JsonReader.cs) + +## Utf8JsonWriter compared to JsonTextWriter + + is a high-performance way to write UTF-8 encoded JSON text from common .NET types like `String`, `Int32`, and `DateTime`. The writer is a low-level type that can be used to build custom serializers. + +The following sections explain recommended programming patterns for using `Utf8JsonWriter`. + +### Write with UTF-8 text + +To achieve the best possible performance while using the `Utf8JsonWriter`, write JSON payloads already encoded as UTF-8 text rather than as UTF-16 strings. Use to cache and pre-encode known string property names and values as statics, and pass those to the writer, rather than using UTF-16 string literals. This is faster than caching and using UTF-8 byte arrays. + +This approach also works if you need to do custom escaping. `System.Text.Json` doesn't let you disable escaping while writing a string. However, you could pass in your own custom as an option to the writer, or create your own `JsonEncodedText` that uses your `JavascriptEncoder` to do the escaping, and then write the `JsonEncodedText` instead of the string. For more information, see [Customize character encoding](system-text-json-how-to.md#customize-character-encoding). + +### Write raw values + +The `Newtonsoft.Json` `WriteRawValue` method writes raw JSON where a value is expected. has no direct equivalent, but here's a workaround that ensures only valid JSON is written: + +```csharp +using JsonDocument doc = JsonDocument.Parse(string); +doc.WriteTo(writer); +``` + +### Customize character escaping + +The [StringEscapeHandling](https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_StringEscapeHandling.htm) setting of `JsonTextWriter` offers options to escape all non-ASCII characters **or** HTML characters. By default, `Utf8JsonWriter` escapes all non-ASCII **and** HTML characters. This escaping is done for defense-in-depth security reasons. To specify a different escaping policy, create a and set . For more information, see [Customize character encoding](system-text-json-how-to.md#customize-character-encoding). + +### Customize JSON format + +`JsonTextWriter` includes the following settings, for which `Utf8JsonWriter` has no equivalent: + +* [Indentation](https://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_JsonTextWriter_Indentation.htm) - Specifies how many characters to indent. `Utf8JsonWriter` always does 2-character indentation. +* [IndentChar](https://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_JsonTextWriter_IndentChar.htm) - Specifies the character to use for indentation. `Utf8JsonWriter` always uses whitespace. +* [QuoteChar](https://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_JsonTextWriter_QuoteChar.htm) - Specifies the character to use to surround string values. `Utf8JsonWriter` always uses double quotes. +* [QuoteName](https://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_JsonTextWriter_QuoteName.htm) - Specifies whether or not to surround property names with quotes. `Utf8JsonWriter` always surrounds them with quotes. + +There are no workarounds that would let you customize the JSON produced by `Utf8JsonWriter` in these ways. + +### Write null values + +To write null values by using `Utf8JsonWriter`, call: + +* to write a key-value pair with null as the value. +* to write null as an element of a JSON array. + +For a string property, if the string is null, and are equivalent to `WriteNull` and `WriteNullValue`. + +### Write Timespan, Uri, or char values + +`JsonTextWriter` provides `WriteValue` methods for [TimeSpan](https://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_JsonTextWriter_WriteValue_18.htm), [Uri](https://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_JsonTextWriter_WriteValue_22.htm), and [char](https://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_JsonTextWriter_WriteValue_3.htm) values. `Utf8JsonWriter` doesn't have equivalent methods. Instead, format these values as strings (by calling `ToString()`, for example) and call . + +### Multi-targeting + +If you need to continue to use `Newtonsoft.Json` for certain target frameworks, you can multi-target and have two implementations. However, this is not trivial and would require some `#ifdefs` and source duplication. One way to share as much code as possible is to create a wrapper around `Utf8JsonWriter` and `Newtonsoft` `JsonTextWriter`. This wrapper would unify the public surface area while isolating the behavioral differences. This lets you isolate the changes mainly to the construction of the type. [Microsoft.Extensions.DependencyModel](https://www.nuget.org/packages/Microsoft.Extensions.DependencyModel/3.1.0/) library follows: + +* [UnifiedJsonWriter.JsonTextWriter.cs](https://github.com/dotnet/runtime/blob/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/installer/managed/Microsoft.Extensions.DependencyModel/UnifiedJsonWriter.JsonTextWriter.cs) +* [UnifiedJsonWriter.Utf8JsonWriter.cs](https://github.com/dotnet/runtime/blob/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/installer/managed/Microsoft.Extensions.DependencyModel/UnifiedJsonWriter.Utf8JsonWriter.cs) + +## Additional resources + + +* [System.Text.Json overview](system-text-json-overview.md) +* [How to use System.Text.Json](system-text-json-how-to.md) +* [How to write custom converters](system-text-json-converters-how-to.md) +* [DateTime and DateTimeOffset support in System.Text.Json](../datetime/system-text-json-support.md) +* [System.Text.Json API reference](xref:System.Text.Json) +* [System.Text.Json.Serialization API reference](xref:System.Text.Json.Serialization) diff --git a/docs/standard/serialization/system-text-json-overview.md b/docs/standard/serialization/system-text-json-overview.md index a0fce4ddf7e71..365e85b29d1cc 100644 --- a/docs/standard/serialization/system-text-json-overview.md +++ b/docs/standard/serialization/system-text-json-overview.md @@ -1,6 +1,6 @@ --- title: "Serialize and deserialize JSON using C# - .NET" -ms.date: "09/16/2019" +ms.date: "01/10/2020" helpviewer_keywords: - "JSON serialization" - "serializing objects" @@ -8,7 +8,7 @@ helpviewer_keywords: - "objects, serializing" --- -# JSON serialization in .NET - overview +# JSON serialization and deserialization (marshalling and unmarshalling) in .NET - overview The `System.Text.Json` namespace provides functionality for serializing to and deserializing from JavaScript Object Notation (JSON). @@ -21,16 +21,15 @@ The library also provides classes for working with an in-memory document object * The library is built-in as part of the [.NET Core 3.0](https://aka.ms/netcore3download) shared framework. * For other target frameworks, install the [System.Text.Json](https://www.nuget.org/packages/System.Text.Json) NuGet package. The package supports: * .NET Standard 2.0 and later versions - * .NET Framework 4.6.1 and later versions + * .NET Framework 4.7.2 and later versions * .NET Core 2.0, 2.1, and 2.2 ## Additional resources * [How to use the library](system-text-json-how-to.md) -* [Source code](https://github.com/dotnet/runtime/tree/master/src/libraries/System.Text.Json) -* [API reference](xref:System.Text.Json) -* [Roadmap](https://github.com/dotnet/runtime/blob/master/src/libraries/System.Text.Json/roadmap/README.md) -* GitHub issues in the dotnet/corefx repository - * [Discussion about the development of System.Text.Json](https://github.com/dotnet/corefx/issues/33115) - * [All System.Text.Json issues](https://github.com/dotnet/runtime/issues?q=is%3Aopen+is%3Aissue+label%3Aarea-System.Text.Json) - * [System.Text.Json issues labeled json-functionality-doc](https://github.com/dotnet/runtime/labels/json-functionality-doc) +* [How to migrate from Newtonsoft.Json](system-text-json-migrate-from-newtonsoft-how-to.md) +* [How to write converters](system-text-json-converters-how-to.md) +* [System.Text.Json source code](https://github.com/dotnet/runtime/tree/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/libraries/System.Text.Json) +* [System.Text.Json API reference](xref:System.Text.Json) +* [System.Text.Json.Serialization API reference](xref:System.Text.Json.Serialization) + diff --git a/docs/standard/serialization/toc.yml b/docs/standard/serialization/toc.yml index c39f5ee1b41c4..a3800a76e6c3a 100644 --- a/docs/standard/serialization/toc.yml +++ b/docs/standard/serialization/toc.yml @@ -9,6 +9,8 @@ href: system-text-json-how-to.md - name: How to write custom converters href: system-text-json-converters-how-to.md + - name: How to migrate from Newtonsoft.Json + href: system-text-json-migrate-from-newtonsoft-how-to.md - name: Binary Serialization href: binary-serialization.md items: