From db7bdade0f8735b6ba5a8a61cf99e5fdedc9794a Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Wed, 27 Nov 2019 13:54:22 -0800 Subject: [PATCH 01/74] initial draft --- .../system-text-json-converters-how-to.md | 121 +---- ...ext-json-migrate-from-newtonsoft-how-to.md | 477 ++++++++++++++++++ 2 files changed, 482 insertions(+), 116 deletions(-) create mode 100644 docs/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to.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 d2f4ecac7905d..8d0b83346c077 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -166,119 +166,10 @@ If multiple custom converters for a type are registered in the `Converters` coll A built-in converter is chosen only if no applicable custom converter is registered. -## Converter samples for common scenarios - -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) -* [Support Dictionary with non-string key](#support-dictionary-with-non-string-key) -* [Support polymorphic deserialization](#support-polymorphic-deserialization) - -### 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`. - -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: - -* `true` and `false` to `Boolean` -* Numbers to `long` or `double` -* Dates to `DateTime` -* Strings to `string` -* Everything else to `JsonElement` - -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/ObjectToInferredTypesConverter.cs)] - -The following code registers the converter: - -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/ConvertInferredTypesToObject.cs?name=SnippetRegister)] - -Here's an example type with `Object` properties: - -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecast.cs?name=SnippetWFWithObjectProperties)] - -The following example of JSON to deserialize contains values that will be deserialized as `DateTime`, `long`, and `string`: - -```json -{ - "Date": "2019-08-01T00:00:00-07:00", - "TemperatureCelsius": 25, - "Summary": "Hot", -} -``` - -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. - -### Support Dictionary with non-string key - -The built-in support for dictionary collections is for `Dictionary`. That is, the key must be a string. To support a dictionary with an integer or some other type as the key, a custom converter is required. - -The following code shows a custom converter that works with `Dictionary`: - -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/DictionaryTKeyEnumTValueConverter.cs)] - -The following code registers the converter: - -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/ConvertDictionaryTkeyEnumTValue.cs?name=SnippetRegister)] - -The converter can serialize and deserialize the `TemperatureRanges` property of the following class that uses the following `Enum`: - -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecast.cs?name=SnippetWFWithEnumDictionary)] - -The JSON output from serialization looks like the following example: - -```json -{ - "Date": "2019-08-01T00:00:00-07:00", - "TemperatureCelsius": 25, - "Summary": "Hot", - "TemperatureRanges": { - "Cold": 20, - "Hot": 40 - } -} -``` - -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 non-string-key dictionaries. - -### Support polymorphic deserialization - -[Polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes) doesn't require a custom converter, but deserialization does require a custom converter. - -Suppose, for example, you have a `Person` abstract base class, with `Employee` and `Customer` derived classes. Polymorphic deserialization means that at design time you can specify `Person` as the deserialization target, and `Customer` and `Employee` objects in the JSON are correctly deserialized at runtime. During deserialization, you have to find clues that identify the required type in the JSON. The kinds of clues available vary with each scenario. For example, a discriminator property might be available or you might have to rely on the presence or absence of a particular property. The current release of `System.Text.Json` doesn't provide attributes to specify how to handle polymorphic deserialization scenarios, so custom converters are required. - -The following code shows a base class, two derived classes, and a custom converter for them. The converter uses a discriminator property to do polymorphic deserialization. The type discriminator isn't in the class definitions but is created during serialization and is read during deserialization. - -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/Person.cs?name=SnippetPerson)] - -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/PersonConverterWithTypeDiscriminator.cs)] - -The following code registers the converter: - -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/ConvertPolymorphic.cs?name=SnippetRegister)] - -The converter can deserialize JSON that was created by using the same converter to serialize, for example: - -```json -[ - { - "TypeDiscriminator": 1, - "CreditLimit": 10000, - "Name": "John" - }, - { - "TypeDiscriminator": 2, - "OfficeNumber": "555-1234", - "Name": "Nancy" - } -] -``` - ## Other custom converter samples +The [Migrate from Newtonsoft Json.NET](system-text-json-how-to.md) article contains samples of custom converters. See the [Workarounds with sample code](system-text-json-migrate-from-newtonsoft-how-to.md#workarounds-with-sample-code) section. + The [unit tests folder](https://github.com/dotnet/corefx/blob/master/src/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 @@ -287,14 +178,12 @@ The [unit tests folder](https://github.com/dotnet/corefx/blob/master/src/System. * `List` converter that accepts external data * `Long[]` converter that works with a comma-delimited list of numbers +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/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters) to serve as a starting point for customization. + ## Additional resources * [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) +* [GitHub issue related to custom converters](https://github.com/dotnet/corefx/issues/36639) 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..7a9ae3e44267c --- /dev/null +++ b/docs/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to.md @@ -0,0 +1,477 @@ +--- +title: "Migrate from Newtonsoft Json.NET to System.Text.Json - .NET" +author: tdykstra +ms.author: tdykstra +ms.date: "12/02/2019" +helpviewer_keywords: + - "JSON serialization" + - "serializing objects" + - "serialization" + - "objects, serializing" +--- + +# How to migrate from Newtonsoft Json.NET to System.Text.Json + +This article shows how to migrate from [Newtonsoft Json.NET](https://www.newtonsoft.com/json) to the JSON serialization tools in the [System.Text.Json namespace](system-text-json-overview.md). + +`System.Text.Json` is relatively new, and its initial focus is on performance, security, and standards compliance. It lacks built-in features to handle some common scenarios, and some default behaviors differ from Newtonsoft. For some scenarios, `System.Text.Json` has no built-in functionality, but workarounds are recommended. For other scenarios, workarounds are impractical. If your application depends on a missing feature that has no workaround, consider delaying your migration to `System.Text.Json`. For information about which features might be added in future releases, see the [Roadmap](https://github.com/dotnet/runtime/tree/master/src/libraries/System.Text.Json/roadmap/README.md). + +Most of this article is about how to use the API, but it also includes guidance on how to use the Document Object Model (DOM) API and the and API. The article is organized into sections in the following order: + +* Differences in default `System.Text.Json.JsonSerializer` behavior compared to Newtonsoft. +* Scenarios that `JsonSerializer` doesn't support, but workarounds might be feasible. [Go to the first of these sections.](#deserialize-inferred-types-to-object-properties) +* Scenarios that `JsonSerializer` doesn't support, and workarounds are relatively difficult or impractical. [Go to the first of these sections.](#types-without-built-in-support). +* [Utf8JsonReader and Utf8JsonWriter](#utf8jsonreader-and-utf8jsonwriter). +* [JsonDocument](#jsondocument). + +## Case-insensitive deserialization + +During deserialization, Newtonsoft does case-insensitive property name matching by default. The `System.Text.Json` default is case-sensitive, which gives better performance. 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. ASP.NET Core specifies the case-insensitive setting when it uses `System.Text.Json`. + +## Comments + +During deserialization, Newtonsoft ignores comments in the JSON by default. The `System.Text.Json` 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 ignores trailing commas by default. In some cases, it ignores multiple trailing commas (for example, `[{"Color":"Red"},{"Color":"Green"},,]`). The `System.Text.Json` default is to throw exceptions for trailing commas because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't include them. For information about how to allow trailing commas, 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. + +## Character escaping + +During serialization, Newtonsoft is relatively permissive about letting characters through without escaping them. (That is, it doesn't replace them with `\uxxxx` where `xxxx` is the Unicode code of the character.) `System.Text.Json` escapes more characters by default to provide defense-in-depth protections against cross-site scripting (XSS) or information disclosure attacks. 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). + +## Converter registration precedence + +The Newtonsoft registration precedence for custom converters is as follows: + +* Attribute on property +* Attribute on type +* `Converters` 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 `System.Text.Json` registration precedence is different: + +* Attribute on property +* `Converters` 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. + +## Newtonsoft [JsonProperty] attribute + +Newtonsoft has a `[JsonProperty]` attribute that is used for a variety of functions. `System.Text.Json` has single-purpose attributes instead of a multi-purpose attribute. The following attributes serve purposes similar to some of the Newtonsoft attribute functions: + +* [[JsonPropertyName]](system-text-json-how-to.md#customize-individual-property-names) +* [[JsonConverter]](system-text-json-converters-how-to.md#register-a-custom-converter) + +Other functions of the Newtonsoft `[JsonProperty]` attribute have no equivalent attribute in `System.Text.Json`. For some of those functions, there are other ways to accomplish the same purpose, as detailed in the following sections of this article. + +## Deserialize inferred types to Object properties + +When deserializing JSON data to a property of type `Object`, Newtonsoft infers the type of a property based on the JSON property value. For example, if a JSON property has "01/01/2020", the deserializer infers that it's a `DateTime`. When `System.Text.Json` deserializes to type `Object`, it always creates a `JsonElement` object. + +The `System.Text.Json` deserializer doesn't guess what type a given property value represents because 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`. + +If your scenario requires type inference for `Object` properties, you can implement a custom converter. The following sample code converts: + +* `true` and `false` to `Boolean` +* Numbers without a decimal to `long` +* Numbers with a decimal to `double` +* Dates to `DateTime` +* Strings to `string` +* Everything else to `JsonElement` + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/ObjectToInferredTypesConverter.cs)] + +The following code registers the converter: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/DeserializeInferredTypesToObject.cs?name=SnippetRegister)] + +Here's an example type with `Object` properties: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecast.cs?name=SnippetWFWithObjectProperties)] + +The following example of JSON to deserialize contains values that will be deserialized as `DateTime`, `long`, and `string`: + +```json +{ + "Date": "2019-08-01T00:00:00-07:00", + "TemperatureCelsius": 25, + "Summary": "Hot", +} +``` + +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. For more information, see issue [38713](https://github.com/dotnet/corefx/issues/38713) in the dotnet/corefx GitHub repository. + +## Dictionary with non-string key + +Newtonsoft supports collections of type `Dictionary`. The built-in support for dictionary collections in `System.Text.Json` 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, a custom converter is required. + +The following code shows a custom converter that works with `Dictionary`: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/DictionaryTKeyEnumTValueConverter.cs)] + +The following code registers the converter: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/RoundtripDictionaryTkeyEnumTValue.cs?name=SnippetRegister)] + +The converter can serialize and deserialize the `TemperatureRanges` property of the following class that uses the following `Enum`: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecast.cs?name=SnippetWFWithEnumDictionary)] + +The JSON output from serialization looks like the following example: + +```json +{ + "Date": "2019-08-01T00:00:00-07:00", + "TemperatureCelsius": 25, + "Summary": "Hot", + "TemperatureRanges": { + "Cold": 20, + "Hot": 40 + } +} +``` + +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 non-string-key dictionaries. For more information, see issue [40120](https://github.com/dotnet/corefx/issues/40120) in the dotnet/corefx GitHub repository. + +## Polymorphic deserialization + +Newtonsoft can do polymorphic serialization and deserialization. Suppose, for example, you have a `Person` abstract base class, with `Employee` and `Customer` derived classes. Polymorphic deserialization means that at design time you can specify `Person` as the deserialization target, and `Customer` and `Employee` objects in the JSON are correctly deserialized at runtime. To do that, the deserializer has to find clues that identify the required type in the JSON. For example, a discriminator property might be available or you might have to rely on the presence or absence of a particular property. Newtonsoft provides attributes that specify how to handle polymorphic deserialization scenarios. The current release of `System.Text.Json` doesn't provide such attributes. If there's no need for polymorphic deserialization, `System.Text.Json` can do [polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes). But the ability to do polymorphic deserialization or convert the same data in both directions requires a custom converter. + +The following code shows a base class, two derived classes, and a custom converter for them. The converter uses a discriminator property to do polymorphic deserialization. The type discriminator isn't in the class definitions but is created during serialization and is read during deserialization. + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/Person.cs?name=SnippetPerson)] + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/PersonConverterWithTypeDiscriminator.cs)] + +The following code registers the converter: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/RoundtripPolymorphic.cs?name=SnippetRegister)] + +The converter can deserialize JSON that was created by using the same converter to serialize, for example: + +```json +[ + { + "TypeDiscriminator": 1, + "CreditLimit": 10000, + "Name": "John" + }, + { + "TypeDiscriminator": 2, + "OfficeNumber": "555-1234", + "Name": "Nancy" + } +] +``` + +For more information, see issue [37787](https://github.com/dotnet/corefx/issues/37787) in the dotnet/corefx GitHub repository. + +## Quoted numbers + +Newtonsoft can serialize or deserialize numbers in quotes, for example, it can accept: `{ "DegreesCelsius":"23" }` instead of `{ "DegreesCelsius":23 }`. To enable that behavior in `System.Text.Json`, implement a custom converter like the following example, which uses quotes for properties defined as `long`. + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/LongToStringConverter.cs)] + +[Register this custom converter](system-text-json-converters-how-to.md#register-a-custom-converter) by using an attribute on individual `long` properties or by adding the converter to the `Converters` collection. + +## Required properties + +During deserialization, `System.Text.Json` 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=SnippetWeatherForecast)] + +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/WeatherForecastPropertyRequiredConverter.cs)] + +[Register this custom converter](system-text-json-converters-how-to.md#register-a-custom-converter) by using an attribute on the POCO class or by adding the converter to the `Converters` collection. + +If you follow this pattern, 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 custom converter calls into itself, making an infinite loop that results in a stack overflow exception. + +This is a simplified example. More complex code would be required if you need to handle attributes (such as `[JsonIgnore]`) or options (such as custom encoders). + +For more information, see issue [38492](https://github.com/dotnet/corefx/issues/38492) in the dotnet/corefx GitHub repository. + +## Deserialize null to non-nullable type + +Newtonsoft doesn't throw an exception in the following scenario: + +* `NullValueHandling` is set to `Ignore` +* During deserialization, the JSON contains a null value for a non-nullable type. + +In the same scenario, `System.Text.Json` does throw an exception. (The corresponding null handling setting is .) + +If you own the target type, the easiest 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](system-text-json-converters-how-to.md#register-a-custom-converter) by using an attribute on the property or by adding the converter to the `Converters` collection. + +For more information, see issue [40922](https://github.com/dotnet/corefx/issues/40922) in the dotnet/corefx GitHub repository. + +## Deserialize to immutable classes and structs + +Newtonsoft can deserialize to immutable classes and structs because it can use constructors that have parameters. The current release of `System.Text.Json` supports only parameterless constructors. But you can use a constructor with a 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](system-text-json-converters-how-to.md#register-a-custom-converter) by adding the converter to the `Converters` 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/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterKeyValuePair.cs). + +For more information, see issues [38569](https://github.com/dotnet/corefx/issues/38569) and [38163](https://github.com/dotnet/corefx/issues/38163) in the dotnet/corefx GitHub repository. Issue + +## Ignore a property at run-time + +The Newtonsoft `DefaultContractResolver` lets you select properties to include or exclude during serialization, based on criteria that are evaluated at run time. `System.Text.Json` provides the following ways to omit properties while serializing: + +* A [[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) flag lets you exclude all null-value properties during serialization. + +These options don't let you selectively omit properties from serialization based on 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#WeatherForecast)] + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecastRuntimeIgnoreConverter.cs)] + +The converter causes the `TemperatureCelsius` property to be omitted from serialization if its value is outside of a specified range. + +[Register this custom converter](system-text-json-converters-how-to.md#register-a-custom-converter) by adding the converter to the `Converters` collection or by applying the `[JsonConvert]` attribute to the class. + +This approach requires complex code if: + +* The POCO includes complex properties. +* You need to handle attributes such as `[JsonIgnore]` or options such as custom encoders. + +For more information, see issue [42001](https://github.com/dotnet/corefx/issues/42001) in the dotnet/corefx GitHub repository. + +## Specify date format + +Newtonsoft provides a `DateTimeZoneHandling` option that lets you specify the serialization format used for `DateTime` and `DateTimeOffset` properties. In `System.Text.Json`, the only format that has built-in support is ISO 8601-1:2019. 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). + +## Callbacks + +Newtonsoft 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 `System.Text.Json`, 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 callback. + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecastCallbacksConverter.cs)] + +[Register the converter](system-text-json-converters-how-to.md#register-a-custom-converter) by adding the converter to the `Converters` collection or by applying the `[JsonConvert]` attribute to the class. + +If you use a custom converter that follows this example: + +* 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. + +For more information, see issue [36639](https://github.com/dotnet/corefx/issues/36639) in the dotnet/corefx GitHub repository. + +## Types without built-in support + +The following list shows some of the types that the current release of `System.Text.Json` doesn't provide built-in support for: + +* and related types. For more information, see issue [38712](https://github.com/dotnet/corefx/issues/38712) in the dotnet/corefx GitHub repository. +* 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). For more information, see issue [38348](https://github.com/dotnet/corefx/issues/38348). +* Collections in the namespace. For more information, see issue [40370](https://github.com/dotnet/corefx/issues/40370). +* The type. For more information, see issue [38007](https://github.com/dotnet/corefx/issues/38007). + +## Private setters + +Newtonsoft can use private property setters. The current release of `System.Text.Json` supports only public setters. For more information, see issue [38163](https://github.com/dotnet/corefx/issues/38163) in the dotnet/corefx GitHub repository. + +## System.Runtime.Serialization attributes + +`System.Text.Json` doesn't support attributes from the `System.Runtime.Serialization` namespace, such as `DataMemberAttribute` and `IgnoreDataMemberAttribute`. This lack of support is a design decision that is not likely to change in the future. + +For more information, see issue [38758](https://github.com/dotnet/corefx/issues/38758) in the dotnet/corefx GitHub repository. + +## Octal numbers + +Newtonsoft treats numbers with a leading zero as octal numbers. `System.Text.Json` doesn't allow leading zeroes because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't allow them. The lack of support for octal numbers is by design and is not expected to change in future versions of `System.Text.Json`. Options for handling JSON that deviates from the specification are offered for only a few high-priority scenarios, such as comments and trailing commas. + +## Object reference handling + +By default, both Newtonsoft and `System.Text.Json` serialize objects 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 offers the option of serializing by reference: + +* A token is added to the JSON created for the first `Person` object. +* The JSON that is created for the second `Person` object contains that token instead of property values. + +For more information, see issues [37786](https://github.com/dotnet/corefx/issues/37786) and [38579](https://github.com/dotnet/corefx/issues/38579) in the dotnet/corefx GitHub repository. + +## Type name handling + +Newtonsoft can add type name metadata to the JSON while serializing, and it uses the metadata while deserializing. The current release of `System.Text.Json` lacks this feature. + +## Populate existing objects + +Newtonsoft can deserialize to an existing instance of a class, instead of creating a new instance. The current release of `System.Text.Json` always creates a new instance of the target type by using the default parameterless constructor. For more information, see issue [37627](https://github.com/dotnet/corefx/issues/37627) and [42515](https://github.com/dotnet/corefx/issues/42515) in the dotnet/corefx GitHub repository. + +## Fields + +Newtonsoft can serialize and deserialize fields as well as properties. The current release of `System.Text.Json` only works with properties. For more information, see issue [36505](https://github.com/dotnet/corefx/issues/36505) in the dotnet/corefx GitHub repository. + +## MissingMemberHandling + +Newtonsoft can be configured to throw exceptions during deserialization if the JSON includes properties that are missing in the target type. `System.Text.Json` 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 lets you debug by using a `TraceWriter` to view logs that are generated by serialization or deserialization. The current release of `System.Text.Json` doesn't do logging. + +## Utf8JsonReader and Utf8JsonWriter + + 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. + + 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 `Utf8JsonReader` and `Utf8JsonWriter`. + +### Ref structs + +The `Utf8JsonReader` and `Utf8JsonWriter` types are *ref structs*, which means they have certain limitations. For example, they can't be stored as a field on a class or struct other than a ref struct. To achieve high performance, these types must be `ref structs` since they need to cache the input or output `Span`, which itself is a ref struct. In addition, these types are mutable since they hold state. Therefore, you should **pass them by ref** rather than by value. Passing them by value would result in a struct copy and the state changes would not be visible to the caller. This differs from Newtonsoft since the Newtonsoft `JsonTextReader` and `JsonTextWriter` are classes. For more information about how to use ref structs, see [Write safe and efficient C# code](../../csharp/write-safe-efficient-code.md). + +### Read with a Stream or PipeReader + +The `Utf8JsonReader` supports reading from a UTF-8 encoded `ReadOnlySpan` or `ReadOnlySequence` (which is the result of reading from a `PipeReader`). 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), you should use the `Encoding.UTF8.GetBytes` API to first transcode the string to a UTF-8 encoded byte array. Then pass that to the `Utf8JsonReader`. 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`, 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` (which is the result of reading from a `PipeReader`), some JSON elements might straddle multiple segments of the `ReadOnlySequence` object. These elements would not be accessible from `ValueSpan` in a contiguous memory block. Instead, whenever you have a multi-segment `ReadOnlySequence` as input, you should always poll the `HasValueSequence` 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; + // ... + } +} +``` + +## Read and write with UTF-8 text + +To achieve the best possible performance while using the `Utf8JsonReader` and `Utf8JsonWriter`, read and write JSON payloads already encoded as UTF-8 text rather than as UTF-16 strings. For example, if you're writing string literals, consider caching them as static byte arrays, and write those instead. For a code example, see [Filter data using Utf8JsonReader](system-text-json-how-to.md#filter-data-using-utf8jsonreader). + +### Read and write null values + +Code that uses the Newtonsoft reader can compare a value token type of String to null, as in the following example: + +```csharp +public static string ReadAsString(this JsonTextReader reader) +{ + reader.Read(); + + if (reader.TokenType != JsonToken.String) + { + throw new InvalidDataException(); + } + + return reader.Value?.ToString(); +} +``` + +This code doesn't work correctly in `System.Text.Json`, which considers the `null` literal to be its own token type. When using `Utf8JsonReader`, check for the `JsonTokenType.Null` token type, as shown in the following example: + +```csharp +public static string ReadAsString(this ref Utf8JsonReader reader) +{ + reader.Read(); + + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + + if (reader.TokenType != JsonTokenType.String) + { + throw new InvalidDataException(); + } + + return reader.GetString(); +} +``` + +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`. + +## Multi-targeting + +If you need to continue to use Newtonsoft 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 `JsonTextReader`, and a wrapper around `Utf8JsonWriter` and `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, along with passing the new type around by reference. This is the pattern that the [.NET Core installer](https://github.com/dotnet/runtime/tree/master/src/installer) follows: + +* [UnifiedJsonReader.JsonTextReader.cs](https://github.com/dotnet/runtime/blob/master/src/installer/managed/Microsoft.Extensions.DependencyModel/UnifiedJsonReader.JsonTextReader.cs) +* [UnifiedJsonReader.Utf8JsonReader.cs](https://github.com/dotnet/runtime/blob/master/src/installer/managed/Microsoft.Extensions.DependencyModel/UnifiedJsonReader.Utf8JsonReader.cs) +* [UnifiedJsonWriter.JsonTextWriter.cs](https://github.com/dotnet/runtime/blob/master/src/installer/managed/Microsoft.Extensions.DependencyModel/UnifiedJsonWriter.JsonTextWriter.cs) +* [UnifiedJsonWriter.Utf8JsonWriter.cs](https://github.com/dotnet/runtime/blob/master/src/installer/managed/Microsoft.Extensions.DependencyModel/UnifiedJsonWriter.Utf8JsonWriter.cs) + +## JsonDocument + + provides the ability to build a read-only Document Object Model (DOM). 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. + +### IDisposable + +`JsonDocument` builds an in-memory view of the data into a pooled buffer. Therefore, unlike Newtonsoft `JObject` or `JArray`, the `JsonDocument` type implements `IDisposable` and needs to be used inside a using block. + +### Read-only + +Since the `System.Text.Json` DOM can't add, remove, or modify JSON elements. If your scenario currently uses a writable DOM, one of the following workarounds might be feasible: + +* To build a `JsonDocument` from scratch, write 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`. For more information, see issue [38589](https://github.com/dotnet/corefx/issues/38589) in the dotnet/corefx GitHub repository. + +### JsonElement + +`JsonDocument` exposes the `RootElement` as a property of type , which is the type that encompasses any JSON element. Newtonsoft uses dedicated 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. + +### Search a JsonDocument + +Searches that use Newtonsoft `JObject` or `JArray` tend to be relatively fast because they're lookups in some dictionary. By comparison, a sequential search through JSON elements stored as `JsonElement` is relatively slow. `System.Text.Json` is designed to minimize initial parse time rather than look-up 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 of every `JsonElement`. 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. + +For a code example, see [Use JsonDocument for access to data](system-text-json-how-to.md#use-jsondocument-for-access-to-data). + +## Additional resources + +* [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) +* [How to write custom converters](system-text-json-converters-how-to.md) +* [Roadmap](https://github.com/dotnet/corefx/blob/master/src/System.Text.Json/roadmap/README.md) From c9e7a21595a2f0f91038523d2b3fa8a48314d8d4 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Thu, 12 Dec 2019 13:52:37 -0800 Subject: [PATCH 02/74] fix links --- .../system-text-json-converters-how-to.md | 18 ++++++------------ .../serialization/system-text-json-how-to.md | 2 +- ...text-json-migrate-from-newtonsoft-how-to.md | 2 +- 3 files changed, 8 insertions(+), 14 deletions(-) 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 8d0b83346c077..0074706159e9b 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -20,11 +20,7 @@ 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: - -* [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). +You can also write custom converters to extend `System.Text.Json` with functionality not included in the current release. For more information, see [How to migrate from Newtonsoft Json.NET to System.Text.Json](system-text-json-migrate-from-newtonsoft-how-to.md). ## Custom converter patterns @@ -56,8 +52,6 @@ The following code shows a custom converter that works with `Dictionary 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 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 [Polymorphic deserialization](system-text-json-migrate-from-newtonsoft-how-to.md#polymorphic-deserialization). -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/master/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,9 +162,9 @@ A built-in converter is chosen only if no applicable custom converter is registe ## Other custom converter samples -The [Migrate from Newtonsoft Json.NET](system-text-json-how-to.md) article contains samples of custom converters. See the [Workarounds with sample code](system-text-json-migrate-from-newtonsoft-how-to.md#workarounds-with-sample-code) section. +The [Migrate from Newtonsoft Json.NET](system-text-json-how-to.md) article contains samples of custom converters. -The [unit tests folder](https://github.com/dotnet/corefx/blob/master/src/System.Text.Json/tests/Serialization/) in the `System.Text.Json.Serialization` source code includes other custom converter samples, such as: +The [unit tests folder](https://github.com/dotnet/runtime/blob/master/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 * `Int32` converter that allows both string and number values on deserialize @@ -185,5 +179,5 @@ If you need to make a converter that modifies the behavior of an existing built- * [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/) +* [Source code for built-in converters](https://github.com/dotnet/runtime/tree/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/) * [GitHub issue related to custom converters](https://github.com/dotnet/corefx/issues/36639) diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index 5ffb4f0e0597f..a49563da2306b 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -498,7 +498,7 @@ In the preceding example scenario, both approaches cause the `WindSpeed` propert } ``` -For information about polymorphic deserialization, see [Support polymorphic deserialization](system-text-json-converters-how-to.md#support-polymorphic-deserialization). +For information about polymorphic deserialization, see [Polymorphic deserialization](system-text-json-migrate-from-newtonsoft-how-to.md#polymorphic-deserialization). ## Allow comments and trailing commas 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 index 7a9ae3e44267c..16b95dc749e60 100644 --- 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 @@ -429,7 +429,7 @@ 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`. +For a string property, if the string is null, and are equivalent to `WriteNull` and `WriteNullValue`. ## Multi-targeting From 88cd2453305ede1c514aeb6390439da635f5d06e Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Fri, 13 Dec 2019 08:37:46 -0800 Subject: [PATCH 03/74] fix link --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 16b95dc749e60..0f163a21b0013 100644 --- 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 @@ -198,7 +198,7 @@ The following JSON is deserialized without error: 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/WeatherForecastPropertyRequiredConverter.cs)] +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecastRequiredPropertyConverter.cs)] [Register this custom converter](system-text-json-converters-how-to.md#register-a-custom-converter) by using an attribute on the POCO class or by adding the converter to the `Converters` collection. From 0f609783f75125743941e694781a31caf265b53e Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Fri, 13 Dec 2019 10:39:31 -0800 Subject: [PATCH 04/74] corrections --- ...ext-json-migrate-from-newtonsoft-how-to.md | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) 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 index 0f163a21b0013..5b8ac32e5680c 100644 --- 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 @@ -14,7 +14,7 @@ helpviewer_keywords: This article shows how to migrate from [Newtonsoft Json.NET](https://www.newtonsoft.com/json) to the JSON serialization tools in the [System.Text.Json namespace](system-text-json-overview.md). -`System.Text.Json` is relatively new, and its initial focus is on performance, security, and standards compliance. It lacks built-in features to handle some common scenarios, and some default behaviors differ from Newtonsoft. For some scenarios, `System.Text.Json` has no built-in functionality, but workarounds are recommended. For other scenarios, workarounds are impractical. If your application depends on a missing feature that has no workaround, consider delaying your migration to `System.Text.Json`. For information about which features might be added in future releases, see the [Roadmap](https://github.com/dotnet/runtime/tree/master/src/libraries/System.Text.Json/roadmap/README.md). +`System.Text.Json` is relatively new, and its initial focus is on performance, security, and standards compliance. It lacks built-in features to handle some common scenarios, and some default behaviors differ from Newtonsoft. For some scenarios, `System.Text.Json` has no built-in functionality, but therre are recommended workarounds. For other scenarios, workarounds are impractical. If your application depends on a missing feature that has no workaround, consider delaying your migration to `System.Text.Json`. For information about which features might be added in future releases, see the [Roadmap](https://github.com/dotnet/runtime/tree/master/src/libraries/System.Text.Json/roadmap/README.md). Most of this article is about how to use the API, but it also includes guidance on how to use the Document Object Model (DOM) API and the and API. The article is organized into sections in the following order: @@ -52,7 +52,7 @@ The Newtonsoft registration precedence for custom converters is as follows: 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 `System.Text.Json` registration precedence is different: +The `System.Text.Json` registration precedence for custom converters is different: * Attribute on property * `Converters` collection @@ -86,9 +86,7 @@ If your scenario requires type inference for `Object` properties, you can implem [!code-csharp[](~/samples/snippets/core/system-text-json/csharp/ObjectToInferredTypesConverter.cs)] -The following code registers the converter: - -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/DeserializeInferredTypesToObject.cs?name=SnippetRegister)] +[Register this custom converter](system-text-json-converters-how-to.md#register-a-custom-converter) by adding it to the `Converters` collection or by using the `[JsonConvert]` attribute on a property. Here's an example type with `Object` properties: @@ -116,9 +114,7 @@ The following code shows a custom converter that works with `Dictionary and are equivalent to `WriteNull` and `WriteNullValue`. -## Multi-targeting +### Multi-targeting If you need to continue to use Newtonsoft 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 `JsonTextReader`, and a wrapper around `Utf8JsonWriter` and `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, along with passing the new type around by reference. This is the pattern that the [.NET Core installer](https://github.com/dotnet/runtime/tree/master/src/installer) follows: From 3c634dc3526d9f4374a6408cd90efea54d181fa6 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Fri, 13 Dec 2019 12:19:50 -0800 Subject: [PATCH 05/74] add new doc to toc --- docs/standard/serialization/toc.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/standard/serialization/toc.yml b/docs/standard/serialization/toc.yml index c39f5ee1b41c4..4af3cba5a30d6 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 Neewtonsoft Json.NET + href: system-text-json-migrate-from-newtonsoft-how-to.md - name: Binary Serialization href: binary-serialization.md items: From d994f56f7d1ea05178c6b3d20008d4eebe51c4c5 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Fri, 13 Dec 2019 13:01:17 -0800 Subject: [PATCH 06/74] add'l notes from ahson email --- ...ystem-text-json-migrate-from-newtonsoft-how-to.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) 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 index 5b8ac32e5680c..6b9d119317463 100644 --- 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 @@ -40,7 +40,7 @@ During deserialization, Newtonsoft ignores trailing commas by default. In some c ## Character escaping -During serialization, Newtonsoft is relatively permissive about letting characters through without escaping them. (That is, it doesn't replace them with `\uxxxx` where `xxxx` is the Unicode code of the character.) `System.Text.Json` escapes more characters by default to provide defense-in-depth protections against cross-site scripting (XSS) or information disclosure attacks. 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). +During serialization, Newtonsoft is relatively permissive about letting characters through without escaping them. (That is, it doesn't replace them with `\uxxxx` where `xxxx` is the Unicode code of the character.) `System.Text.Json` escapes more characters by default to provide defense-in-depth protections against cross-site scripting (XSS) or information disclosure attacks. `System.Text.Json` escapes all non-ASCII characters by default, so you don't need to do anything if you're using `StringEscapeHandling.EscapeNonAscii`. 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). ## Converter registration precedence @@ -71,7 +71,7 @@ Other functions of the Newtonsoft `[JsonProperty]` attribute have no equivalent ## Deserialize inferred types to Object properties -When deserializing JSON data to a property of type `Object`, Newtonsoft infers the type of a property based on the JSON property value. For example, if a JSON property has "01/01/2020", the deserializer infers that it's a `DateTime`. When `System.Text.Json` deserializes to type `Object`, it always creates a `JsonElement` object. +When deserializing JSON data to a property of type `Object`, Newtonsoft infers the type of a property based on the JSON property value. For example, if a JSON property has "2020-01-01T05:40Z", the Newtonsoft deserializer infers that it's a `DateTime` unless you specify `DateParseHandling.None`. When `System.Text.Json` deserializes to type `Object`, it always creates a `JsonElement` object. The `System.Text.Json` deserializer doesn't guess what type a given property value represents because 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`. @@ -223,7 +223,7 @@ For more information, see issue [40922](https://github.com/dotnet/corefx/issues/ ## Deserialize to immutable classes and structs -Newtonsoft can deserialize to immutable classes and structs because it can use constructors that have parameters. The current release of `System.Text.Json` supports only parameterless constructors. But you can use a constructor with a parameters in a custom converter. +Newtonsoft can deserialize to immutable classes and structs because it can use constructors that have parameters. The current release of `System.Text.Json` supports only 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: @@ -237,7 +237,11 @@ And here's a converter that serializes and deserializes this struct: 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/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterKeyValuePair.cs). -For more information, see issues [38569](https://github.com/dotnet/corefx/issues/38569) and [38163](https://github.com/dotnet/corefx/issues/38163) in the dotnet/corefx GitHub repository. Issue +For more information, see issues [38569](https://github.com/dotnet/corefx/issues/38569) and [38163](https://github.com/dotnet/corefx/issues/38163) in the dotnet/corefx GitHub repository. + +## Specify constructor to use + +The Newtonsoft `[JsonConstructor]` attribute lets you specify which constructor to call when deserializing to a POCO. The current release of `System.Text.Json` 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). ## Ignore a property at run-time From 6d4216c975bc92769b1441527c284fdb9afc6189 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Fri, 13 Dec 2019 14:59:31 -0800 Subject: [PATCH 07/74] fix issue numbers --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) 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 index 6b9d119317463..67839f6ffc1f2 100644 --- 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 @@ -165,7 +165,7 @@ The converter can deserialize JSON that was created by using the same converter ] ``` -For more information, see issue [37787](https://github.com/dotnet/corefx/issues/37787) in the dotnet/corefx GitHub repository. +For more information, see issue [38650](https://github.com/dotnet/corefx/issues/38650) and issue [39031](https://github.com/dotnet/corefx/issues/39031) in the dotnet/corefx GitHub repository. ## Quoted numbers @@ -175,6 +175,8 @@ Newtonsoft can serialize or deserialize numbers in quotes. For example, it can a [Register this custom converter](system-text-json-converters-how-to.md#register-a-custom-converter) by using an attribute on individual `long` properties or by adding the converter to the `Converters` collection. +For more information, see issue [39473](https://github.com/dotnet/corefx/issues/39473) in the dotnet/corefx GitHub repository. + ## Required properties During deserialization, `System.Text.Json` 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: @@ -237,7 +239,7 @@ And here's a converter that serializes and deserializes this struct: 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/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterKeyValuePair.cs). -For more information, see issues [38569](https://github.com/dotnet/corefx/issues/38569) and [38163](https://github.com/dotnet/corefx/issues/38163) in the dotnet/corefx GitHub repository. +For more information, see issue [38569](https://github.com/dotnet/corefx/issues/38569) in the dotnet/corefx GitHub repository. ## Specify constructor to use @@ -265,11 +267,11 @@ This approach requires complex code if: * The POCO includes complex properties. * You need to handle attributes such as `[JsonIgnore]` or options such as custom encoders. -For more information, see issue [42001](https://github.com/dotnet/corefx/issues/42001) in the dotnet/corefx GitHub repository. +For more information, see issue [42001](https://github.com/dotnet/corefx/issues/42001) and issue [40600](https://github.com/dotnet/corefx/issues/40600) in the dotnet/corefx GitHub repository. ## Specify date format -Newtonsoft provides a `DateTimeZoneHandling` option that lets you specify the serialization format used for `DateTime` and `DateTimeOffset` properties. In `System.Text.Json`, the only format that has built-in support is ISO 8601-1:2019. 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). +Newtonsoft provides a `DateTimeZoneHandling` option that lets you specify the serialization format used for `DateTime` and `DateTimeOffset` properties. In `System.Text.Json`, the only format that has built-in support is ISO 8601-1:2019. 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) and issue [41456](https://github.com/dotnet/corefx/issues/41456) in the dotnet/corefx GitHub repository. ## Callbacks From 2594e499bc9798a59ab5e4626a1293471799be96 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Fri, 13 Dec 2019 15:33:53 -0800 Subject: [PATCH 08/74] comment out roadmap link --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 index 67839f6ffc1f2..448ed96698efd 100644 --- 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 @@ -14,7 +14,9 @@ helpviewer_keywords: This article shows how to migrate from [Newtonsoft Json.NET](https://www.newtonsoft.com/json) to the JSON serialization tools in the [System.Text.Json namespace](system-text-json-overview.md). -`System.Text.Json` is relatively new, and its initial focus is on performance, security, and standards compliance. It lacks built-in features to handle some common scenarios, and some default behaviors differ from Newtonsoft. For some scenarios, `System.Text.Json` has no built-in functionality, but therre are recommended workarounds. For other scenarios, workarounds are impractical. If your application depends on a missing feature that has no workaround, consider delaying your migration to `System.Text.Json`. For information about which features might be added in future releases, see the [Roadmap](https://github.com/dotnet/runtime/tree/master/src/libraries/System.Text.Json/roadmap/README.md). +`System.Text.Json` is relatively new, and its initial focus is on performance, security, and standards compliance. It lacks built-in features to handle some common scenarios, and some default behaviors differ from Newtonsoft. For some scenarios, `System.Text.Json` has no built-in functionality, but therre are recommended workarounds. For other scenarios, workarounds are impractical. If your application depends on a missing feature that has no workaround, consider delaying your migration to `System.Text.Json`. + + Most of this article is about how to use the API, but it also includes guidance on how to use the Document Object Model (DOM) API and the and API. The article is organized into sections in the following order: @@ -474,4 +476,4 @@ For a code example, see [Use JsonDocument for access to data](system-text-json-h * [System.Text.Json API reference](xref:System.Text.Json) * [How to use System.Text.Json](system-text-json-how-to.md) * [How to write custom converters](system-text-json-converters-how-to.md) -* [Roadmap](https://github.com/dotnet/corefx/blob/master/src/System.Text.Json/roadmap/README.md) +* From 823b58160761bfc809c77254d19fe6687ba96da9 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Sat, 14 Dec 2019 17:06:35 -0800 Subject: [PATCH 09/74] incorporate info from roadmap --- ...ext-json-migrate-from-newtonsoft-how-to.md | 64 +++++++++++++------ 1 file changed, 43 insertions(+), 21 deletions(-) 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 index 448ed96698efd..23fe37288bb9e 100644 --- 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 @@ -167,7 +167,13 @@ The converter can deserialize JSON that was created by using the same converter ] ``` -For more information, see issue [38650](https://github.com/dotnet/corefx/issues/38650) and issue [39031](https://github.com/dotnet/corefx/issues/39031) in the dotnet/corefx GitHub repository. +For more information, see the following issues in the dotnet/corefx GitHub repository: + +* [38650](https://github.com/dotnet/corefx/issues/38650) Support polymorphic serialization +* [39031](https://github.com/dotnet/corefx/issues/39031) Support polymorphic deserialization +* [41758](https://github.com/dotnet/corefx/issues/41758) System.Text.Json ignores JsonPropertyName on base class +* [38154](https://github.com/dotnet/corefx/issues/38154) New modifier is not hiding base property +* [39905](https://github.com/dotnet/corefx/issues/39905) Allow custom converters for base-classes ## Quoted numbers @@ -247,14 +253,25 @@ For more information, see issue [38569](https://github.com/dotnet/corefx/issues/ The Newtonsoft `[JsonConstructor]` attribute lets you specify which constructor to call when deserializing to a POCO. The current release of `System.Text.Json` 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). -## Ignore a property at run-time +## Conditionally ignore a property + +Newtonsoft 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` setting on `JsonSerializerOptions` lets you specify that all null-value properties should be ignored. +* The `NullValueHandling` setting on `[JsonProperty]` attribute lets you specify individual properties that should be ignored when null. + +`System.Text.Json` provides the following ways to omit properties while serializing: -The Newtonsoft `DefaultContractResolver` lets you select properties to include or exclude during serialization, based on criteria that are evaluated at run time. `System.Text.Json` 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. -* A [[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) flag lets you exclude all null-value properties during serialization. +These options don't let you: -These options don't let you selectively omit properties from serialization based on 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: +* 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)] @@ -306,10 +323,27 @@ The following list shows some of the types that the current release of `System.T * Collections in the namespace. For more information, see issue [40370](https://github.com/dotnet/corefx/issues/40370). * The type. For more information, see issue [38007](https://github.com/dotnet/corefx/issues/38007). +## Fields + +Newtonsoft can serialize and deserialize fields as well as properties. The current release of `System.Text.Json` only works with properties. For more information, see issue [36505](https://github.com/dotnet/corefx/issues/36505) in the dotnet/corefx GitHub repository. + ## Private setters Newtonsoft can use private property setters. The current release of `System.Text.Json` supports only public setters. For more information, see issue [38163](https://github.com/dotnet/corefx/issues/38163) in the dotnet/corefx GitHub repository. +## Preserve object references and handle loops + +By default, Newtonsoft 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 has a `PreserveReferencesHandling` setting on `JsonSerializerSettings` that lets you serialize by reference: + +* A token is added to the JSON created for the first `Person` object. +* The JSON that is created for the second `Person` object contains that token instead of property values. + +Newtonsoft also has a `ReferenceLoopHandling` setting that lets you ignore circular references rather than throw an exception. + +The current release of `System.Text.Json` supports only serialization by value. For more information, see issues [37786](https://github.com/dotnet/corefx/issues/37786), [38579](https://github.com/dotnet/corefx/issues/38579), and [41002](https://github.com/dotnet/corefx/issues/41002) in the dotnet/corefx GitHub repository. + ## System.Runtime.Serialization attributes `System.Text.Json` doesn't support attributes from the `System.Runtime.Serialization` namespace, such as `DataMemberAttribute` and `IgnoreDataMemberAttribute`. This lack of support is a design decision that is not likely to change in the future. @@ -320,27 +354,15 @@ For more information, see issue [38758](https://github.com/dotnet/corefx/issues/ Newtonsoft treats numbers with a leading zero as octal numbers. `System.Text.Json` doesn't allow leading zeroes because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't allow them. The lack of support for octal numbers is by design and is not expected to change in future versions of `System.Text.Json`. Options for handling JSON that deviates from the specification are offered for only a few high-priority scenarios, such as comments and trailing commas. -## Object reference handling - -By default, both Newtonsoft and `System.Text.Json` serialize objects 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 offers the option of serializing by reference: - -* A token is added to the JSON created for the first `Person` object. -* The JSON that is created for the second `Person` object contains that token instead of property values. - -For more information, see issues [37786](https://github.com/dotnet/corefx/issues/37786) and [38579](https://github.com/dotnet/corefx/issues/38579) in the dotnet/corefx GitHub repository. - ## Type name handling -Newtonsoft can add type name metadata to the JSON while serializing, and it uses the metadata while deserializing. The current release of `System.Text.Json` lacks this feature. +Newtonsoft has a `TypeNameHandling` setting that adds type name metadata to the JSON while serializing, and it uses the metadata while deserializing. The current release of `System.Text.Json` lacks this feature. For more information, see issue [39031](https://github.com/dotnet/corefx/issues/39031) in the dotnet/corefx GitHub repository. + ## Populate existing objects Newtonsoft can deserialize to an existing instance of a class, instead of creating a new instance. The current release of `System.Text.Json` always creates a new instance of the target type by using the default parameterless constructor. For more information, see issue [37627](https://github.com/dotnet/corefx/issues/37627) and [42515](https://github.com/dotnet/corefx/issues/42515) in the dotnet/corefx GitHub repository. -## Fields - -Newtonsoft can serialize and deserialize fields as well as properties. The current release of `System.Text.Json` only works with properties. For more information, see issue [36505](https://github.com/dotnet/corefx/issues/36505) in the dotnet/corefx GitHub repository. - ## MissingMemberHandling Newtonsoft can be configured to throw exceptions during deserialization if the JSON includes properties that are missing in the target type. `System.Text.Json` 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. @@ -455,7 +477,7 @@ If you need to continue to use Newtonsoft for certain target frameworks, you can Since the `System.Text.Json` DOM can't add, remove, or modify JSON elements. If your scenario currently uses a writable DOM, one of the following workarounds might be feasible: * To build a `JsonDocument` from scratch, write 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`. For more information, see issue [38589](https://github.com/dotnet/corefx/issues/38589) in the dotnet/corefx GitHub repository. +* 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`. For more information, see issue [38589](https://github.com/dotnet/corefx/issues/38589) and issue [39922](https://github.com/dotnet/corefx/issues/39922) in the dotnet/corefx GitHub repository. ### JsonElement From 7dd85d6d5e062a77d03ec6ba433449e8b0126de5 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Sun, 15 Dec 2019 10:32:16 -0800 Subject: [PATCH 10/74] more info from roadmap --- ...ext-json-migrate-from-newtonsoft-how-to.md | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) 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 index 23fe37288bb9e..ccefdcb9f3b3a 100644 --- 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 @@ -258,8 +258,8 @@ The Newtonsoft `[JsonConstructor]` attribute lets you specify which constructor Newtonsoft 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` setting on `JsonSerializerOptions` lets you specify that all null-value properties should be ignored. -* The `NullValueHandling` setting on `[JsonProperty]` attribute lets you specify individual properties that should be ignored when null. +* The `NullValueHandling` and `DefaultValueHandling` setting on `JsonSerializerOptions` lets you specify that all null-value or default-value properties should be ignored. +* The `NullValueHandling` and `DefaultValueHandling` setting on `[JsonProperty]` attribute lets you specify individual properties that should be ignored when set to null or default value. `System.Text.Json` provides the following ways to omit properties while serializing: @@ -268,7 +268,9 @@ Newtonsoft has several ways to conditionally ignore a property on serialization These options don't let you: -* Ignore selected properties if their value is null. +* 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: @@ -286,7 +288,11 @@ This approach requires complex code if: * The POCO includes complex properties. * You need to handle attributes such as `[JsonIgnore]` or options such as custom encoders. -For more information, see issue [42001](https://github.com/dotnet/corefx/issues/42001) and issue [40600](https://github.com/dotnet/corefx/issues/40600) in the dotnet/corefx GitHub repository. +For more information, see the following issues in the dotnet/corefx GitHub repository: + +* [42001](https://github.com/dotnet/corefx/issues/42001) Equivalent of DefaultContractResolver +* [40600](https://github.com/dotnet/corefx/issues/40600) Ignore selected properties when null +* [38878](https://github.com/dotnet/corefx/issues/38878) Ignore default values ## Specify date format @@ -316,12 +322,16 @@ For more information, see issue [36639](https://github.com/dotnet/corefx/issues/ ## Types without built-in support -The following list shows some of the types that the current release of `System.Text.Json` doesn't provide built-in support for: +`System.Text.Json` doesn't provide built-in support for the following types. The list includes links to the issues that track the request for support: -* and related types. For more information, see issue [38712](https://github.com/dotnet/corefx/issues/38712) in the dotnet/corefx GitHub repository. -* 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). For more information, see issue [38348](https://github.com/dotnet/corefx/issues/38348). -* Collections in the namespace. For more information, see issue [40370](https://github.com/dotnet/corefx/issues/40370). -* The type. For more information, see issue [38007](https://github.com/dotnet/corefx/issues/38007). +* and related types. [38712](https://github.com/dotnet/corefx/issues/38712) +* 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). [38348](https://github.com/dotnet/corefx/issues/38348) +* Collection types in the namespace. [40370](https://github.com/dotnet/corefx/issues/40370) +* . [38007](https://github.com/dotnet/corefx/issues/38007) +* . [41348](https://github.com/dotnet/corefx/issues/41348) +* . [33458](https://github.com/dotnet/corefx/issues/33458) +* . [38641](https://github.com/dotnet/corefx/issues/38641) +* . [418](https://github.com/dotnet/runtime/issues/418) ## Fields @@ -358,10 +368,17 @@ Newtonsoft treats numbers with a leading zero as octal numbers. `System.Text.Jso Newtonsoft has a `TypeNameHandling` setting that adds type name metadata to the JSON while serializing, and it uses the metadata while deserializing. The current release of `System.Text.Json` lacks this feature. For more information, see issue [39031](https://github.com/dotnet/corefx/issues/39031) in the dotnet/corefx GitHub repository. - ## Populate existing objects -Newtonsoft can deserialize to an existing instance of a class, instead of creating a new instance. The current release of `System.Text.Json` always creates a new instance of the target type by using the default parameterless constructor. For more information, see issue [37627](https://github.com/dotnet/corefx/issues/37627) and [42515](https://github.com/dotnet/corefx/issues/42515) in the dotnet/corefx GitHub repository. +The Newtonsoft `JsonConvert.PopulateObject` method deserializes a JSON document to an existing instance of a class, instead of creating a new instance. The current release of `System.Text.Json` always creates a new instance of the target type by using the default parameterless constructor. For more information, see issue [37627](https://github.com/dotnet/corefx/issues/37627) in the dotnet/corefx GitHub repository. + +## Reuse rather than replace properties + +The Newtonsoft `ObjetCreationHandling` setting lets you specify that objects in properties should be reused rather than replaced during deserialization. The current release of `System.Text.Json` always replaces objects in properties. For more information, see issue [42515](https://github.com/dotnet/corefx/issues/42515) in the dotnet/corefx GitHub repository. + +## Add to collections without setters + +During deserialization, Newtonsoft adds objects to a collection even if the property has no setter. The current release of `System.Text.Json` ignores properties that don't have setters. For more information, see issue [39477](https://github.com/dotnet/corefx/issues/39477) in the dotnet/corefx GitHub repository. ## MissingMemberHandling From 3a2ab3d504cca7ac00f3834267fc85da6247a461 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Mon, 16 Dec 2019 17:27:10 -0800 Subject: [PATCH 11/74] address thraka feedback --- docs/standard/serialization/system-text-json-how-to.md | 2 +- .../system-text-json-migrate-from-newtonsoft-how-to.md | 6 +++--- docs/standard/serialization/toc.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index a49563da2306b..d15ad418d62c9 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -498,7 +498,7 @@ In the preceding example scenario, both approaches cause the `WindSpeed` propert } ``` -For information about polymorphic deserialization, see [Polymorphic deserialization](system-text-json-migrate-from-newtonsoft-how-to.md#polymorphic-deserialization). +This section shows how to do **serialization**. For information about polymorphic **deserialization**, see [Polymorphic deserialization](system-text-json-migrate-from-newtonsoft-how-to.md#polymorphic-deserialization). ## Allow comments and trailing commas 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 index ccefdcb9f3b3a..88dbdb2949bda 100644 --- 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 @@ -12,13 +12,13 @@ helpviewer_keywords: # How to migrate from Newtonsoft Json.NET to System.Text.Json -This article shows how to migrate from [Newtonsoft Json.NET](https://www.newtonsoft.com/json) to the JSON serialization tools in the [System.Text.Json namespace](system-text-json-overview.md). +This article shows how to migrate from [Newtonsoft Json.NET](https://www.newtonsoft.com/json) to the classes and methods in the [System.Text.Json namespace](system-text-json-overview.md). -`System.Text.Json` is relatively new, and its initial focus is on performance, security, and standards compliance. It lacks built-in features to handle some common scenarios, and some default behaviors differ from Newtonsoft. For some scenarios, `System.Text.Json` has no built-in functionality, but therre are recommended workarounds. For other scenarios, workarounds are impractical. If your application depends on a missing feature that has no workaround, consider delaying your migration to `System.Text.Json`. + `System.Text.Json` focuses primarily on performance, security, and standards compliance. It lacks built-in features to handle some common scenarios, and some default behaviors differ from Newtonsoft. 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 that has no workaround, consider delaying your migration to `System.Text.Json`. -Most of this article is about how to use the API, but it also includes guidance on how to use the Document Object Model (DOM) API and the and API. The article is organized into sections in the following order: +Most of this article is about how to use the API, but it also includes guidance on how to use the Document Object Model (DOM) and the and API. The article is organized into sections in the following order: * Differences in default `System.Text.Json.JsonSerializer` behavior compared to Newtonsoft. * Scenarios that `JsonSerializer` doesn't support, but workarounds might be feasible. [Go to the first of these sections.](#deserialize-inferred-types-to-object-properties) diff --git a/docs/standard/serialization/toc.yml b/docs/standard/serialization/toc.yml index 4af3cba5a30d6..6cea1fe7fb9c2 100644 --- a/docs/standard/serialization/toc.yml +++ b/docs/standard/serialization/toc.yml @@ -9,7 +9,7 @@ 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 Neewtonsoft Json.NET + - name: How to migrate from Newtonsoft Json.NET href: system-text-json-migrate-from-newtonsoft-how-to.md - name: Binary Serialization href: binary-serialization.md From c546273a3fd9544037ce918305884c946b30a03c Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Mon, 16 Dec 2019 17:44:09 -0800 Subject: [PATCH 12/74] Newtonsoft --> Json.NET --- ...ext-json-migrate-from-newtonsoft-how-to.md | 80 +++++++++---------- 1 file changed, 40 insertions(+), 40 deletions(-) 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 index 88dbdb2949bda..bfa7c8a682b3f 100644 --- 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 @@ -14,13 +14,13 @@ helpviewer_keywords: This article shows how to migrate from [Newtonsoft Json.NET](https://www.newtonsoft.com/json) to the classes and methods in the [System.Text.Json namespace](system-text-json-overview.md). - `System.Text.Json` focuses primarily on performance, security, and standards compliance. It lacks built-in features to handle some common scenarios, and some default behaviors differ from Newtonsoft. 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 that has no workaround, consider delaying your migration to `System.Text.Json`. + `System.Text.Json` focuses primarily on performance, security, and standards compliance. It lacks built-in features to handle some common scenarios, and some default behaviors differ from Json.NET. 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 that has no workaround, consider delaying your migration to `System.Text.Json`. Most of this article is about how to use the API, but it also includes guidance on how to use the Document Object Model (DOM) and the and API. The article is organized into sections in the following order: -* Differences in default `System.Text.Json.JsonSerializer` behavior compared to Newtonsoft. +* Differences in default `System.Text.Json.JsonSerializer` behavior compared to Json.NET. * Scenarios that `JsonSerializer` doesn't support, but workarounds might be feasible. [Go to the first of these sections.](#deserialize-inferred-types-to-object-properties) * Scenarios that `JsonSerializer` doesn't support, and workarounds are relatively difficult or impractical. [Go to the first of these sections.](#types-without-built-in-support). * [Utf8JsonReader and Utf8JsonWriter](#utf8jsonreader-and-utf8jsonwriter). @@ -28,25 +28,25 @@ Most of this article is about how to use the `. The built-in support for dictionary collections in `System.Text.Json` 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, a custom converter is required. +Json.NET supports collections of type `Dictionary`. The built-in support for dictionary collections in `System.Text.Json` 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, a custom converter is required. The following code shows a custom converter that works with `Dictionary`: @@ -140,7 +140,7 @@ The [unit tests folder](https://github.com/dotnet/corefx/blob/master/src/System. ## Polymorphic deserialization -Newtonsoft can do polymorphic serialization and deserialization. Suppose, for example, you have a `Person` abstract base class, with `Employee` and `Customer` derived classes. Polymorphic deserialization means that at design time you can specify `Person` as the deserialization target, and `Customer` and `Employee` objects in the JSON are correctly deserialized at runtime. To do that, the deserializer has to find clues that identify the required type in the JSON. For example, a discriminator property might be available or you might have to rely on the presence or absence of a particular property. Newtonsoft provides attributes that specify how to handle polymorphic deserialization scenarios. The current release of `System.Text.Json` doesn't provide such attributes. If there's no need for polymorphic deserialization, `System.Text.Json` can do [polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes). But the ability to do polymorphic deserialization or convert the same data in both directions requires a custom converter. +Json.NET can do polymorphic serialization and deserialization. Suppose, for example, you have a `Person` abstract base class, with `Employee` and `Customer` derived classes. Polymorphic deserialization means that at design time you can specify `Person` as the deserialization target, and `Customer` and `Employee` objects in the JSON are correctly deserialized at runtime. To do that, the deserializer has to find clues that identify the required type in the JSON. For example, a discriminator property might be available or you might have to rely on the presence or absence of a particular property. Json.NET provides attributes that specify how to handle polymorphic deserialization scenarios. The current release of `System.Text.Json` doesn't provide such attributes. If there's no need for polymorphic deserialization, `System.Text.Json` can do [polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes). But the ability to do polymorphic deserialization or convert the same data in both directions requires a custom converter. The following code shows a base class, two derived classes, and a custom converter for them. The converter uses a discriminator property to do polymorphic deserialization. The type discriminator isn't in the class definitions but is created during serialization and is read during deserialization. @@ -177,7 +177,7 @@ For more information, see the following issues in the dotnet/corefx GitHub repos ## Quoted numbers -Newtonsoft can serialize or deserialize numbers in quotes. For example, it can accept: `{ "DegreesCelsius":"23" }` instead of `{ "DegreesCelsius":23 }`. To enable that behavior in `System.Text.Json`, implement a custom converter like the following example, which uses quotes for properties defined as `long`. +Json.NET can serialize or deserialize numbers in quotes. For example, it can accept: `{ "DegreesCelsius":"23" }` instead of `{ "DegreesCelsius":23 }`. To enable that behavior in `System.Text.Json`, implement a custom converter like the following example, which uses quotes for properties defined as `long`. [!code-csharp[](~/samples/snippets/core/system-text-json/csharp/LongToStringConverter.cs)] @@ -214,7 +214,7 @@ For more information, see issue [38492](https://github.com/dotnet/corefx/issues/ ## Deserialize null to non-nullable type -Newtonsoft doesn't throw an exception in the following scenario: +Json.NET doesn't throw an exception in the following scenario: * `NullValueHandling` is set to `Ignore` * During deserialization, the JSON contains a null value for a non-nullable type. @@ -233,7 +233,7 @@ For more information, see issue [40922](https://github.com/dotnet/corefx/issues/ ## Deserialize to immutable classes and structs -Newtonsoft can deserialize to immutable classes and structs because it can use constructors that have parameters. The current release of `System.Text.Json` supports only parameterless constructors. As a workaround, you can call a constructor with parameters in a custom converter. +Json.NET can deserialize to immutable classes and structs because it can use constructors that have parameters. The current release of `System.Text.Json` supports only 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: @@ -251,11 +251,11 @@ For more information, see issue [38569](https://github.com/dotnet/corefx/issues/ ## Specify constructor to use -The Newtonsoft `[JsonConstructor]` attribute lets you specify which constructor to call when deserializing to a POCO. The current release of `System.Text.Json` 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). +The Json.NET `[JsonConstructor]` attribute lets you specify which constructor to call when deserializing to a POCO. The current release of `System.Text.Json` 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 has several ways to conditionally ignore a property on serialization or deserialization: +Json.NET 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` setting on `JsonSerializerOptions` lets you specify that all null-value or default-value properties should be ignored. @@ -296,18 +296,18 @@ For more information, see the following issues in the dotnet/corefx GitHub repos ## Specify date format -Newtonsoft provides a `DateTimeZoneHandling` option that lets you specify the serialization format used for `DateTime` and `DateTimeOffset` properties. In `System.Text.Json`, the only format that has built-in support is ISO 8601-1:2019. 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) and issue [41456](https://github.com/dotnet/corefx/issues/41456) in the dotnet/corefx GitHub repository. +Json.NET provides a `DateTimeZoneHandling` option that lets you specify the serialization format used for `DateTime` and `DateTimeOffset` properties. In `System.Text.Json`, the only format that has built-in support is ISO 8601-1:2019. 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) and issue [41456](https://github.com/dotnet/corefx/issues/41456) in the dotnet/corefx GitHub repository. ## Callbacks -Newtonsoft lets you execute custom code at several points in the serialization or deserialization process: +Json.NET 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 `System.Text.Json`, 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 callback. +In `System.Text.Json`, 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 Json.NET callback. [!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecastCallbacksConverter.cs)] @@ -335,22 +335,22 @@ For more information, see issue [36639](https://github.com/dotnet/corefx/issues/ ## Fields -Newtonsoft can serialize and deserialize fields as well as properties. The current release of `System.Text.Json` only works with properties. For more information, see issue [36505](https://github.com/dotnet/corefx/issues/36505) in the dotnet/corefx GitHub repository. +Json.NET can serialize and deserialize fields as well as properties. The current release of `System.Text.Json` only works with properties. For more information, see issue [36505](https://github.com/dotnet/corefx/issues/36505) in the dotnet/corefx GitHub repository. ## Private setters -Newtonsoft can use private property setters. The current release of `System.Text.Json` supports only public setters. For more information, see issue [38163](https://github.com/dotnet/corefx/issues/38163) in the dotnet/corefx GitHub repository. +Json.NET can use private property setters. The current release of `System.Text.Json` supports only public setters. For more information, see issue [38163](https://github.com/dotnet/corefx/issues/38163) in the dotnet/corefx GitHub repository. ## Preserve object references and handle loops -By default, Newtonsoft 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. +By default, Json.NET 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 has a `PreserveReferencesHandling` setting on `JsonSerializerSettings` that lets you serialize by reference: +Json.NET has a `PreserveReferencesHandling` setting on `JsonSerializerSettings` that lets you serialize by reference: * A token is added to the JSON created for the first `Person` object. * The JSON that is created for the second `Person` object contains that token instead of property values. -Newtonsoft also has a `ReferenceLoopHandling` setting that lets you ignore circular references rather than throw an exception. +Json.NET also has a `ReferenceLoopHandling` setting that lets you ignore circular references rather than throw an exception. The current release of `System.Text.Json` supports only serialization by value. For more information, see issues [37786](https://github.com/dotnet/corefx/issues/37786), [38579](https://github.com/dotnet/corefx/issues/38579), and [41002](https://github.com/dotnet/corefx/issues/41002) in the dotnet/corefx GitHub repository. @@ -362,31 +362,31 @@ For more information, see issue [38758](https://github.com/dotnet/corefx/issues/ ## Octal numbers -Newtonsoft treats numbers with a leading zero as octal numbers. `System.Text.Json` doesn't allow leading zeroes because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't allow them. The lack of support for octal numbers is by design and is not expected to change in future versions of `System.Text.Json`. Options for handling JSON that deviates from the specification are offered for only a few high-priority scenarios, such as comments and trailing commas. +Json.NET treats numbers with a leading zero as octal numbers. `System.Text.Json` doesn't allow leading zeroes because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't allow them. The lack of support for octal numbers is by design and is not expected to change in future versions of `System.Text.Json`. Options for handling JSON that deviates from the specification are offered for only a few high-priority scenarios, such as comments and trailing commas. ## Type name handling -Newtonsoft has a `TypeNameHandling` setting that adds type name metadata to the JSON while serializing, and it uses the metadata while deserializing. The current release of `System.Text.Json` lacks this feature. For more information, see issue [39031](https://github.com/dotnet/corefx/issues/39031) in the dotnet/corefx GitHub repository. +Json.NET has a `TypeNameHandling` setting that adds type name metadata to the JSON while serializing, and it uses the metadata while deserializing. The current release of `System.Text.Json` lacks this feature. For more information, see issue [39031](https://github.com/dotnet/corefx/issues/39031) in the dotnet/corefx GitHub repository. ## Populate existing objects -The Newtonsoft `JsonConvert.PopulateObject` method deserializes a JSON document to an existing instance of a class, instead of creating a new instance. The current release of `System.Text.Json` always creates a new instance of the target type by using the default parameterless constructor. For more information, see issue [37627](https://github.com/dotnet/corefx/issues/37627) in the dotnet/corefx GitHub repository. +The Json.NET `JsonConvert.PopulateObject` method deserializes a JSON document to an existing instance of a class, instead of creating a new instance. The current release of `System.Text.Json` always creates a new instance of the target type by using the default parameterless constructor. For more information, see issue [37627](https://github.com/dotnet/corefx/issues/37627) in the dotnet/corefx GitHub repository. ## Reuse rather than replace properties -The Newtonsoft `ObjetCreationHandling` setting lets you specify that objects in properties should be reused rather than replaced during deserialization. The current release of `System.Text.Json` always replaces objects in properties. For more information, see issue [42515](https://github.com/dotnet/corefx/issues/42515) in the dotnet/corefx GitHub repository. +The Json.NET `ObjetCreationHandling` setting lets you specify that objects in properties should be reused rather than replaced during deserialization. The current release of `System.Text.Json` always replaces objects in properties. For more information, see issue [42515](https://github.com/dotnet/corefx/issues/42515) in the dotnet/corefx GitHub repository. ## Add to collections without setters -During deserialization, Newtonsoft adds objects to a collection even if the property has no setter. The current release of `System.Text.Json` ignores properties that don't have setters. For more information, see issue [39477](https://github.com/dotnet/corefx/issues/39477) in the dotnet/corefx GitHub repository. +During deserialization, Json.NET adds objects to a collection even if the property has no setter. The current release of `System.Text.Json` ignores properties that don't have setters. For more information, see issue [39477](https://github.com/dotnet/corefx/issues/39477) in the dotnet/corefx GitHub repository. ## MissingMemberHandling -Newtonsoft can be configured to throw exceptions during deserialization if the JSON includes properties that are missing in the target type. `System.Text.Json` 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. +Json.NET can be configured to throw exceptions during deserialization if the JSON includes properties that are missing in the target type. `System.Text.Json` 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 lets you debug by using a `TraceWriter` to view logs that are generated by serialization or deserialization. The current release of `System.Text.Json` doesn't do logging. +Json.NET lets you debug by using a `TraceWriter` to view logs that are generated by serialization or deserialization. The current release of `System.Text.Json` doesn't do logging. ## Utf8JsonReader and Utf8JsonWriter @@ -398,7 +398,7 @@ The following sections explain recommended programming patterns for using `Utf8J ### Ref structs -The `Utf8JsonReader` and `Utf8JsonWriter` types are *ref structs*, which means they have certain limitations. For example, they can't be stored as a field on a class or struct other than a ref struct. To achieve high performance, these types must be `ref structs` since they need to cache the input or output `Span`, which itself is a ref struct. In addition, these types are mutable since they hold state. Therefore, you should **pass them by ref** rather than by value. Passing them by value would result in a struct copy and the state changes would not be visible to the caller. This differs from Newtonsoft since the Newtonsoft `JsonTextReader` and `JsonTextWriter` are classes. For more information about how to use ref structs, see [Write safe and efficient C# code](../../csharp/write-safe-efficient-code.md). +The `Utf8JsonReader` and `Utf8JsonWriter` types are *ref structs*, which means they have certain limitations. For example, they can't be stored as a field on a class or struct other than a ref struct. To achieve high performance, these types must be `ref structs` since they need to cache the input or output `Span`, which itself is a ref struct. In addition, these types are mutable since they hold state. Therefore, you should **pass them by ref** rather than by value. Passing them by value would result in a struct copy and the state changes would not be visible to the caller. This differs from Json.NET since the Json.NET `JsonTextReader` and `JsonTextWriter` are classes. For more information about how to use ref structs, see [Write safe and efficient C# code](../../csharp/write-safe-efficient-code.md). ### Read with a Stream or PipeReader @@ -428,7 +428,7 @@ To achieve the best possible performance while using the `Utf8JsonReader` and `U ### Read and write null values -Code that uses the Newtonsoft reader can compare a value token type of String to null, as in the following example: +Code that uses the Json.NET reader can compare a value token type of String to null, as in the following example: ```csharp public static string ReadAsString(this JsonTextReader reader) @@ -474,7 +474,7 @@ For a string property, if the string is null, , which is the type that encompasses any JSON element. Newtonsoft uses dedicated 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. +`JsonDocument` exposes the `RootElement` as a property of type , which is the type that encompasses any JSON element. Json.NET uses dedicated 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. ### Search a JsonDocument -Searches that use Newtonsoft `JObject` or `JArray` tend to be relatively fast because they're lookups in some dictionary. By comparison, a sequential search through JSON elements stored as `JsonElement` is relatively slow. `System.Text.Json` is designed to minimize initial parse time rather than look-up time. Therefore, use the following approaches to optimize performance when searching through a `JsonDocument` object: +Searches that use Json.NET `JObject` or `JArray` tend to be relatively fast because they're lookups in some dictionary. By comparison, a sequential search through JSON elements stored as `JsonElement` is relatively slow. `System.Text.Json` is designed to minimize initial parse time rather than look-up 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 of every `JsonElement`. 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. From 07cc1595f3186d2cce5d8317f61728e30bc75f50 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Mon, 16 Dec 2019 18:20:04 -0800 Subject: [PATCH 13/74] omit 'the current release of' --- ...ext-json-migrate-from-newtonsoft-how-to.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) 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 index bfa7c8a682b3f..9d0dabb854b5a 100644 --- 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 @@ -140,7 +140,7 @@ The [unit tests folder](https://github.com/dotnet/corefx/blob/master/src/System. ## Polymorphic deserialization -Json.NET can do polymorphic serialization and deserialization. Suppose, for example, you have a `Person` abstract base class, with `Employee` and `Customer` derived classes. Polymorphic deserialization means that at design time you can specify `Person` as the deserialization target, and `Customer` and `Employee` objects in the JSON are correctly deserialized at runtime. To do that, the deserializer has to find clues that identify the required type in the JSON. For example, a discriminator property might be available or you might have to rely on the presence or absence of a particular property. Json.NET provides attributes that specify how to handle polymorphic deserialization scenarios. The current release of `System.Text.Json` doesn't provide such attributes. If there's no need for polymorphic deserialization, `System.Text.Json` can do [polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes). But the ability to do polymorphic deserialization or convert the same data in both directions requires a custom converter. +Json.NET can do polymorphic serialization and deserialization. Suppose, for example, you have a `Person` abstract base class, with `Employee` and `Customer` derived classes. Polymorphic deserialization means that at design time you can specify `Person` as the deserialization target, and `Customer` and `Employee` objects in the JSON are correctly deserialized at runtime. To do that, the deserializer has to find clues that identify the required type in the JSON. For example, a discriminator property might be available or you might have to rely on the presence or absence of a particular property. Json.NET provides attributes that specify how to handle polymorphic deserialization scenarios. `System.Text.Json` doesn't provide such attributes. If there's no need for polymorphic deserialization, `System.Text.Json` can do [polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes). But the ability to do polymorphic deserialization or convert the same data in both directions requires a custom converter. The following code shows a base class, two derived classes, and a custom converter for them. The converter uses a discriminator property to do polymorphic deserialization. The type discriminator isn't in the class definitions but is created during serialization and is read during deserialization. @@ -233,7 +233,7 @@ For more information, see issue [40922](https://github.com/dotnet/corefx/issues/ ## Deserialize to immutable classes and structs -Json.NET can deserialize to immutable classes and structs because it can use constructors that have parameters. The current release of `System.Text.Json` supports only parameterless constructors. As a workaround, you can call a constructor with parameters in a custom converter. +Json.NET can deserialize to immutable classes and structs because it can use constructors that have parameters. `System.Text.Json` supports only 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: @@ -251,7 +251,7 @@ For more information, see issue [38569](https://github.com/dotnet/corefx/issues/ ## Specify constructor to use -The Json.NET `[JsonConstructor]` attribute lets you specify which constructor to call when deserializing to a POCO. The current release of `System.Text.Json` 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). +The Json.NET `[JsonConstructor]` attribute lets you specify which constructor to call when deserializing to a POCO. `System.Text.Json` 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 @@ -335,11 +335,11 @@ For more information, see issue [36639](https://github.com/dotnet/corefx/issues/ ## Fields -Json.NET can serialize and deserialize fields as well as properties. The current release of `System.Text.Json` only works with properties. For more information, see issue [36505](https://github.com/dotnet/corefx/issues/36505) in the dotnet/corefx GitHub repository. +Json.NET can serialize and deserialize fields as well as properties. `System.Text.Json` only works with properties. For more information, see issue [36505](https://github.com/dotnet/corefx/issues/36505) in the dotnet/corefx GitHub repository. ## Private setters -Json.NET can use private property setters. The current release of `System.Text.Json` supports only public setters. For more information, see issue [38163](https://github.com/dotnet/corefx/issues/38163) in the dotnet/corefx GitHub repository. +Json.NET can use private property setters. `System.Text.Json` supports only public setters. For more information, see issue [38163](https://github.com/dotnet/corefx/issues/38163) in the dotnet/corefx GitHub repository. ## Preserve object references and handle loops @@ -352,7 +352,7 @@ Json.NET has a `PreserveReferencesHandling` setting on `JsonSerializerSettings` Json.NET also has a `ReferenceLoopHandling` setting that lets you ignore circular references rather than throw an exception. -The current release of `System.Text.Json` supports only serialization by value. For more information, see issues [37786](https://github.com/dotnet/corefx/issues/37786), [38579](https://github.com/dotnet/corefx/issues/38579), and [41002](https://github.com/dotnet/corefx/issues/41002) in the dotnet/corefx GitHub repository. +`System.Text.Json` supports only serialization by value. For more information, see issues [37786](https://github.com/dotnet/corefx/issues/37786), [38579](https://github.com/dotnet/corefx/issues/38579), and [41002](https://github.com/dotnet/corefx/issues/41002) in the dotnet/corefx GitHub repository. ## System.Runtime.Serialization attributes @@ -366,19 +366,19 @@ Json.NET treats numbers with a leading zero as octal numbers. `System.Text.Json` ## Type name handling -Json.NET has a `TypeNameHandling` setting that adds type name metadata to the JSON while serializing, and it uses the metadata while deserializing. The current release of `System.Text.Json` lacks this feature. For more information, see issue [39031](https://github.com/dotnet/corefx/issues/39031) in the dotnet/corefx GitHub repository. +Json.NET has a `TypeNameHandling` setting that adds type name metadata to the JSON while serializing, and it uses the metadata while deserializing. `System.Text.Json` lacks this feature. For more information, see issue [39031](https://github.com/dotnet/corefx/issues/39031) in the dotnet/corefx GitHub repository. ## Populate existing objects -The Json.NET `JsonConvert.PopulateObject` method deserializes a JSON document to an existing instance of a class, instead of creating a new instance. The current release of `System.Text.Json` always creates a new instance of the target type by using the default parameterless constructor. For more information, see issue [37627](https://github.com/dotnet/corefx/issues/37627) in the dotnet/corefx GitHub repository. +The Json.NET `JsonConvert.PopulateObject` method deserializes a JSON document to an existing instance of a class, instead of creating a new instance. `System.Text.Json` always creates a new instance of the target type by using the default parameterless constructor. For more information, see issue [37627](https://github.com/dotnet/corefx/issues/37627) in the dotnet/corefx GitHub repository. ## Reuse rather than replace properties -The Json.NET `ObjetCreationHandling` setting lets you specify that objects in properties should be reused rather than replaced during deserialization. The current release of `System.Text.Json` always replaces objects in properties. For more information, see issue [42515](https://github.com/dotnet/corefx/issues/42515) in the dotnet/corefx GitHub repository. +The Json.NET `ObjetCreationHandling` setting lets you specify that objects in properties should be reused rather than replaced during deserialization. `System.Text.Json` always replaces objects in properties. For more information, see issue [42515](https://github.com/dotnet/corefx/issues/42515) in the dotnet/corefx GitHub repository. ## Add to collections without setters -During deserialization, Json.NET adds objects to a collection even if the property has no setter. The current release of `System.Text.Json` ignores properties that don't have setters. For more information, see issue [39477](https://github.com/dotnet/corefx/issues/39477) in the dotnet/corefx GitHub repository. +During deserialization, Json.NET adds objects to a collection even if the property has no setter. `System.Text.Json` ignores properties that don't have setters. For more information, see issue [39477](https://github.com/dotnet/corefx/issues/39477) in the dotnet/corefx GitHub repository. ## MissingMemberHandling @@ -386,7 +386,7 @@ Json.NET can be configured to throw exceptions during deserialization if the JSO ## TraceWriter -Json.NET lets you debug by using a `TraceWriter` to view logs that are generated by serialization or deserialization. The current release of `System.Text.Json` doesn't do logging. +Json.NET lets you debug by using a `TraceWriter` to view logs that are generated by serialization or deserialization. `System.Text.Json` doesn't do logging. ## Utf8JsonReader and Utf8JsonWriter From 20f10957070883125656e71234e88b13198499d9 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Mon, 16 Dec 2019 18:21:59 -0800 Subject: [PATCH 14/74] omit 'by design' --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index 9d0dabb854b5a..f90c19d835ed2 100644 --- 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 @@ -356,13 +356,13 @@ Json.NET also has a `ReferenceLoopHandling` setting that lets you ignore circula ## System.Runtime.Serialization attributes -`System.Text.Json` doesn't support attributes from the `System.Runtime.Serialization` namespace, such as `DataMemberAttribute` and `IgnoreDataMemberAttribute`. This lack of support is a design decision that is not likely to change in the future. +`System.Text.Json` doesn't support attributes from the `System.Runtime.Serialization` namespace, such as `DataMemberAttribute` and `IgnoreDataMemberAttribute`. For more information, see issue [38758](https://github.com/dotnet/corefx/issues/38758) in the dotnet/corefx GitHub repository. ## Octal numbers -Json.NET treats numbers with a leading zero as octal numbers. `System.Text.Json` doesn't allow leading zeroes because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't allow them. The lack of support for octal numbers is by design and is not expected to change in future versions of `System.Text.Json`. Options for handling JSON that deviates from the specification are offered for only a few high-priority scenarios, such as comments and trailing commas. +Json.NET treats numbers with a leading zero as octal numbers. `System.Text.Json` doesn't allow leading zeroes because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't allow them. ## Type name handling From 41019bcbf0fd4859594d0ee782c33c1962da1fc2 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Mon, 16 Dec 2019 18:36:40 -0800 Subject: [PATCH 15/74] link to exact hash instead of branch --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 index f90c19d835ed2..160648c5ff4d8 100644 --- 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 @@ -476,10 +476,10 @@ For a string property, if the string is null, Date: Tue, 17 Dec 2019 07:44:08 -0800 Subject: [PATCH 16/74] Json.NET --> Newtonsoft.Json --- .../system-text-json-converters-how-to.md | 4 +- .../serialization/system-text-json-how-to.md | 2 +- ...ext-json-migrate-from-newtonsoft-how-to.md | 91 ++++++++++--------- docs/standard/serialization/toc.yml | 2 +- 4 files changed, 51 insertions(+), 48 deletions(-) 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 0074706159e9b..19904081a3073 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -20,7 +20,7 @@ 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. For more information, see [How to migrate from Newtonsoft Json.NET to System.Text.Json](system-text-json-migrate-from-newtonsoft-how-to.md). +You can also write custom converters to extend `System.Text.Json` with functionality not included in the current release. For more information, see [How to migrate from Newtonsoft.Json to System.Text.Json](system-text-json-migrate-from-newtonsoft-how-to.md). ## Custom converter patterns @@ -162,7 +162,7 @@ A built-in converter is chosen only if no applicable custom converter is registe ## Other custom converter samples -The [Migrate from Newtonsoft Json.NET](system-text-json-how-to.md) article contains samples of custom converters. +The [Migrate from Newtonsoft.Json to System.Text.Json](system-text-json-migrate-from-newtonsoft-how-to.md) article contains samples of custom converters. The [unit tests folder](https://github.com/dotnet/runtime/blob/master/src/libraries/System.Text.Json/tests/Serialization/) in the `System.Text.Json.Serialization` source code includes other custom converter samples, such as: diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index d15ad418d62c9..02b62108c1b7a 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -498,7 +498,7 @@ In the preceding example scenario, both approaches cause the `WindSpeed` propert } ``` -This section shows how to do **serialization**. For information about polymorphic **deserialization**, see [Polymorphic deserialization](system-text-json-migrate-from-newtonsoft-how-to.md#polymorphic-deserialization). +This section shows how to do **serialization**. For information about polymorphic **deserialization**, see [How to migrate from Newtonsoft.Json to System.Text.Json](system-text-json-migrate-from-newtonsoft-how-to.md#polymorphic-deserialization). ## Allow comments and trailing commas 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 index 160648c5ff4d8..f70cad5d9b312 100644 --- 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 @@ -1,5 +1,5 @@ --- -title: "Migrate from Newtonsoft Json.NET to System.Text.Json - .NET" +title: "Migrate from Newtonsoft.Json to System.Text.Json - .NET" author: tdykstra ms.author: tdykstra ms.date: "12/02/2019" @@ -10,17 +10,17 @@ helpviewer_keywords: - "objects, serializing" --- -# How to migrate from Newtonsoft Json.NET to System.Text.Json +# How to migrate from Newtonsoft.Json to System.Text.Json -This article shows how to migrate from [Newtonsoft Json.NET](https://www.newtonsoft.com/json) to the classes and methods in the [System.Text.Json namespace](system-text-json-overview.md). +This article shows how to migrate from [Newtonsoft.Json](https://www.newtonsoft.com/json) to [System.Text.Json](system-text-json-overview.md). - `System.Text.Json` focuses primarily on performance, security, and standards compliance. It lacks built-in features to handle some common scenarios, and some default behaviors differ from Json.NET. 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 that has no workaround, consider delaying your migration to `System.Text.Json`. + `System.Text.Json` focuses primarily on performance, security, and standards compliance. It lacks built-in features to handle some common scenarios, and some default behaviors differ from `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 that has no workaround, consider delaying your migration to `System.Text.Json`. Most of this article is about how to use the API, but it also includes guidance on how to use the Document Object Model (DOM) and the and API. The article is organized into sections in the following order: -* Differences in default `System.Text.Json.JsonSerializer` behavior compared to Json.NET. +* Differences in default `System.Text.Json.JsonSerializer` behavior compared to `Newtonsoft.Json`. * Scenarios that `JsonSerializer` doesn't support, but workarounds might be feasible. [Go to the first of these sections.](#deserialize-inferred-types-to-object-properties) * Scenarios that `JsonSerializer` doesn't support, and workarounds are relatively difficult or impractical. [Go to the first of these sections.](#types-without-built-in-support). * [Utf8JsonReader and Utf8JsonWriter](#utf8jsonreader-and-utf8jsonwriter). @@ -28,25 +28,25 @@ Most of this article is about how to use the `. The built-in support for dictionary collections in `System.Text.Json` 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, a custom converter is required. +`Newtonsoft.Json` supports collections of type `Dictionary`. The built-in support for dictionary collections in `System.Text.Json` 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, a custom converter is required. The following code shows a custom converter that works with `Dictionary`: @@ -140,7 +140,7 @@ The [unit tests folder](https://github.com/dotnet/corefx/blob/master/src/System. ## Polymorphic deserialization -Json.NET can do polymorphic serialization and deserialization. Suppose, for example, you have a `Person` abstract base class, with `Employee` and `Customer` derived classes. Polymorphic deserialization means that at design time you can specify `Person` as the deserialization target, and `Customer` and `Employee` objects in the JSON are correctly deserialized at runtime. To do that, the deserializer has to find clues that identify the required type in the JSON. For example, a discriminator property might be available or you might have to rely on the presence or absence of a particular property. Json.NET provides attributes that specify how to handle polymorphic deserialization scenarios. `System.Text.Json` doesn't provide such attributes. If there's no need for polymorphic deserialization, `System.Text.Json` can do [polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes). But the ability to do polymorphic deserialization or convert the same data in both directions requires a custom converter. +`Newtonsoft.Json` can do polymorphic serialization and deserialization. Suppose, for example, you have a `Person` abstract base class, with `Employee` and `Customer` derived classes. Polymorphic deserialization means that at design time you can specify `Person` as the deserialization target, and `Customer` and `Employee` objects in the JSON are correctly deserialized at runtime. To do that, the deserializer has to find clues that identify the required type in the JSON. For example, a discriminator property might be available or you might have to rely on the presence or absence of a particular property. `Newtonsoft.Json` provides attributes that specify how to handle polymorphic deserialization scenarios. `System.Text.Json` doesn't provide such attributes. If there's no need for polymorphic deserialization, `System.Text.Json` can do [polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes). But the ability to do polymorphic deserialization or convert the same data in both directions requires a custom converter. The following code shows a base class, two derived classes, and a custom converter for them. The converter uses a discriminator property to do polymorphic deserialization. The type discriminator isn't in the class definitions but is created during serialization and is read during deserialization. @@ -177,7 +177,7 @@ For more information, see the following issues in the dotnet/corefx GitHub repos ## Quoted numbers -Json.NET can serialize or deserialize numbers in quotes. For example, it can accept: `{ "DegreesCelsius":"23" }` instead of `{ "DegreesCelsius":23 }`. To enable that behavior in `System.Text.Json`, implement a custom converter like the following example, which uses quotes for properties defined as `long`. +`Newtonsoft.Json` can serialize or deserialize numbers in quotes. For example, it can accept: `{ "DegreesCelsius":"23" }` instead of `{ "DegreesCelsius":23 }`. To enable that behavior in `System.Text.Json`, implement a custom converter like the following example, which uses quotes for properties defined as `long`. [!code-csharp[](~/samples/snippets/core/system-text-json/csharp/LongToStringConverter.cs)] @@ -214,7 +214,7 @@ For more information, see issue [38492](https://github.com/dotnet/corefx/issues/ ## Deserialize null to non-nullable type -Json.NET doesn't throw an exception in the following scenario: +`Newtonsoft.Json` doesn't throw an exception in the following scenario: * `NullValueHandling` is set to `Ignore` * During deserialization, the JSON contains a null value for a non-nullable type. @@ -233,7 +233,7 @@ For more information, see issue [40922](https://github.com/dotnet/corefx/issues/ ## Deserialize to immutable classes and structs -Json.NET can deserialize to immutable classes and structs because it can use constructors that have parameters. `System.Text.Json` supports only parameterless constructors. As a workaround, you can call a constructor with parameters in a custom converter. +`Newtonsoft.Json` can deserialize to immutable classes and structs because it can use constructors that have parameters. `System.Text.Json` supports only 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: @@ -251,11 +251,11 @@ For more information, see issue [38569](https://github.com/dotnet/corefx/issues/ ## Specify constructor to use -The Json.NET `[JsonConstructor]` attribute lets you specify which constructor to call when deserializing to a POCO. `System.Text.Json` 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). +The `Newtonsoft.Json` `[JsonConstructor]` attribute lets you specify which constructor to call when deserializing to a POCO. `System.Text.Json` 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 -Json.NET has several ways to conditionally ignore a property on serialization or deserialization: +`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` setting on `JsonSerializerOptions` lets you specify that all null-value or default-value properties should be ignored. @@ -296,18 +296,18 @@ For more information, see the following issues in the dotnet/corefx GitHub repos ## Specify date format -Json.NET provides a `DateTimeZoneHandling` option that lets you specify the serialization format used for `DateTime` and `DateTimeOffset` properties. In `System.Text.Json`, the only format that has built-in support is ISO 8601-1:2019. 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) and issue [41456](https://github.com/dotnet/corefx/issues/41456) in the dotnet/corefx GitHub repository. +`Newtonsoft.Json` provides a `DateTimeZoneHandling` option that lets you specify the serialization format used for `DateTime` and `DateTimeOffset` properties. In `System.Text.Json`, the only format that has built-in support is ISO 8601-1:2019. 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) and issue [41456](https://github.com/dotnet/corefx/issues/41456) in the dotnet/corefx GitHub repository. ## Callbacks -Json.NET lets you execute custom code at several points in the serialization or deserialization process: +`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 `System.Text.Json`, 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 Json.NET callback. +In `System.Text.Json`, 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)] @@ -335,24 +335,27 @@ For more information, see issue [36639](https://github.com/dotnet/corefx/issues/ ## Fields -Json.NET can serialize and deserialize fields as well as properties. `System.Text.Json` only works with properties. For more information, see issue [36505](https://github.com/dotnet/corefx/issues/36505) in the dotnet/corefx GitHub repository. +`Newtonsoft.Json` can serialize and deserialize fields as well as properties. `System.Text.Json` only works with properties. For more information, see issue [36505](https://github.com/dotnet/corefx/issues/36505) in the dotnet/corefx GitHub repository. ## Private setters -Json.NET can use private property setters. `System.Text.Json` supports only public setters. For more information, see issue [38163](https://github.com/dotnet/corefx/issues/38163) in the dotnet/corefx GitHub repository. +`Newtonsoft.Json` can use private property setters. `System.Text.Json` supports only public setters. For more information, see issue [38163](https://github.com/dotnet/corefx/issues/38163) in the dotnet/corefx GitHub repository. ## Preserve object references and handle loops -By default, Json.NET 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. +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. -Json.NET has a `PreserveReferencesHandling` setting on `JsonSerializerSettings` that lets you serialize by reference: +`Newtonsoft.Json` has a `PreserveReferencesHandling` setting on `JsonSerializerSettings` that lets you serialize by reference: * A token is added to the JSON created for the first `Person` object. * The JSON that is created for the second `Person` object contains that token instead of property values. -Json.NET also has a `ReferenceLoopHandling` setting that lets you ignore circular references rather than throw an exception. +`Newtonsoft.Json` also has a `ReferenceLoopHandling` setting that lets you ignore circular references rather than throw an exception. -`System.Text.Json` supports only serialization by value. For more information, see issues [37786](https://github.com/dotnet/corefx/issues/37786), [38579](https://github.com/dotnet/corefx/issues/38579), and [41002](https://github.com/dotnet/corefx/issues/41002) in the dotnet/corefx GitHub repository. +`System.Text.Json` supports only serialization by value. For more information, see the following issues in the dotnet/corefx GitHub repository: + +* [37786](https://github.com/dotnet/corefx/issues/37786) Support for object references +* [41002](https://github.com/dotnet/corefx/issues/41002) Circular reference handling ## System.Runtime.Serialization attributes @@ -362,31 +365,31 @@ For more information, see issue [38758](https://github.com/dotnet/corefx/issues/ ## Octal numbers -Json.NET treats numbers with a leading zero as octal numbers. `System.Text.Json` doesn't allow leading zeroes because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't allow them. +`Newtonsoft.Json` treats numbers with a leading zero as octal numbers. `System.Text.Json` doesn't allow leading zeroes because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't allow them. ## Type name handling -Json.NET has a `TypeNameHandling` setting that adds type name metadata to the JSON while serializing, and it uses the metadata while deserializing. `System.Text.Json` lacks this feature. For more information, see issue [39031](https://github.com/dotnet/corefx/issues/39031) in the dotnet/corefx GitHub repository. +`Newtonsoft.Json` has a `TypeNameHandling` setting that adds type name metadata to the JSON while serializing, and it uses the metadata while deserializing. `System.Text.Json` lacks this feature. For more information, see issue [39031](https://github.com/dotnet/corefx/issues/39031) in the dotnet/corefx GitHub repository. ## Populate existing objects -The Json.NET `JsonConvert.PopulateObject` method deserializes a JSON document to an existing instance of a class, instead of creating a new instance. `System.Text.Json` always creates a new instance of the target type by using the default parameterless constructor. For more information, see issue [37627](https://github.com/dotnet/corefx/issues/37627) in the dotnet/corefx GitHub repository. +The `Newtonsoft.Json` `JsonConvert.PopulateObject` method deserializes a JSON document to an existing instance of a class, instead of creating a new instance. `System.Text.Json` always creates a new instance of the target type by using the default parameterless constructor. For more information, see issue [37627](https://github.com/dotnet/corefx/issues/37627) in the dotnet/corefx GitHub repository. ## Reuse rather than replace properties -The Json.NET `ObjetCreationHandling` setting lets you specify that objects in properties should be reused rather than replaced during deserialization. `System.Text.Json` always replaces objects in properties. For more information, see issue [42515](https://github.com/dotnet/corefx/issues/42515) in the dotnet/corefx GitHub repository. +The `Newtonsoft.Json` `ObjetCreationHandling` setting lets you specify that objects in properties should be reused rather than replaced during deserialization. `System.Text.Json` always replaces objects in properties. For more information, see issue [42515](https://github.com/dotnet/corefx/issues/42515) in the dotnet/corefx GitHub repository. ## Add to collections without setters -During deserialization, Json.NET adds objects to a collection even if the property has no setter. `System.Text.Json` ignores properties that don't have setters. For more information, see issue [39477](https://github.com/dotnet/corefx/issues/39477) in the dotnet/corefx GitHub repository. +During deserialization, `Newtonsoft.Json` adds objects to a collection even if the property has no setter. `System.Text.Json` ignores properties that don't have setters. For more information, see issue [39477](https://github.com/dotnet/corefx/issues/39477) in the dotnet/corefx GitHub repository. ## MissingMemberHandling -Json.NET can be configured to throw exceptions during deserialization if the JSON includes properties that are missing in the target type. `System.Text.Json` 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. +`Newtonsoft.Json` can be configured to throw exceptions during deserialization if the JSON includes properties that are missing in the target type. `System.Text.Json` 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 -Json.NET lets you debug by using a `TraceWriter` to view logs that are generated by serialization or deserialization. `System.Text.Json` doesn't do logging. +`Newtonsoft.Json` lets you debug by using a `TraceWriter` to view logs that are generated by serialization or deserialization. `System.Text.Json` doesn't do logging. ## Utf8JsonReader and Utf8JsonWriter @@ -398,7 +401,7 @@ The following sections explain recommended programming patterns for using `Utf8J ### Ref structs -The `Utf8JsonReader` and `Utf8JsonWriter` types are *ref structs*, which means they have certain limitations. For example, they can't be stored as a field on a class or struct other than a ref struct. To achieve high performance, these types must be `ref structs` since they need to cache the input or output `Span`, which itself is a ref struct. In addition, these types are mutable since they hold state. Therefore, you should **pass them by ref** rather than by value. Passing them by value would result in a struct copy and the state changes would not be visible to the caller. This differs from Json.NET since the Json.NET `JsonTextReader` and `JsonTextWriter` are classes. For more information about how to use ref structs, see [Write safe and efficient C# code](../../csharp/write-safe-efficient-code.md). +The `Utf8JsonReader` and `Utf8JsonWriter` types are *ref structs*, which means they have certain limitations. For example, they can't be stored as a field on a class or struct other than a ref struct. To achieve high performance, these types must be `ref structs` since they need to cache the input or output `Span`, which itself is a ref struct. In addition, these types are mutable since they hold state. Therefore, you should **pass them by ref** rather than by value. Passing them 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` and `JsonTextWriter` are classes. For more information about how to use ref structs, see [Write safe and efficient C# code](../../csharp/write-safe-efficient-code.md). ### Read with a Stream or PipeReader @@ -428,7 +431,7 @@ To achieve the best possible performance while using the `Utf8JsonReader` and `U ### Read and write null values -Code that uses the Json.NET reader can compare a value token type of String to null, as in the following example: +Code that uses the `Newtonsoft.Json` reader can compare a value token type of String to null, as in the following example: ```csharp public static string ReadAsString(this JsonTextReader reader) @@ -474,7 +477,7 @@ For a string property, if the string is null, , which is the type that encompasses any JSON element. Json.NET uses dedicated 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. +`JsonDocument` exposes the `RootElement` as a property of type , which is the type that encompasses any JSON element. `Newtonsoft.Json` uses dedicated 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. ### Search a JsonDocument -Searches that use Json.NET `JObject` or `JArray` tend to be relatively fast because they're lookups in some dictionary. By comparison, a sequential search through JSON elements stored as `JsonElement` is relatively slow. `System.Text.Json` is designed to minimize initial parse time rather than look-up time. Therefore, use the following approaches to optimize performance when searching through a `JsonDocument` object: +Searches that use `Newtonsoft.Json` `JObject` or `JArray` tend to be relatively fast because they're lookups in some dictionary. By comparison, a sequential search through JSON elements stored as `JsonElement` is relatively slow. `System.Text.Json` is designed to minimize initial parse time rather than look-up 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 of every `JsonElement`. 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. diff --git a/docs/standard/serialization/toc.yml b/docs/standard/serialization/toc.yml index 6cea1fe7fb9c2..a3800a76e6c3a 100644 --- a/docs/standard/serialization/toc.yml +++ b/docs/standard/serialization/toc.yml @@ -9,7 +9,7 @@ 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.NET + - name: How to migrate from Newtonsoft.Json href: system-text-json-migrate-from-newtonsoft-how-to.md - name: Binary Serialization href: binary-serialization.md From 7243deb0a57926edae7efe16a1c6d207c28584b2 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 17 Dec 2019 08:15:08 -0800 Subject: [PATCH 17/74] scrub additional resources sections --- .../system-text-json-converters-how-to.md | 9 ++++++--- .../serialization/system-text-json-how-to.md | 7 ++++--- ...-text-json-migrate-from-newtonsoft-how-to.md | 5 +++-- .../serialization/system-text-json-overview.md | 17 ++++++++++------- 4 files changed, 23 insertions(+), 15 deletions(-) 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 19904081a3073..3b679f22af186 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -176,8 +176,11 @@ If you need to make a converter that modifies the behavior of an existing built- ## Additional resources +* [GitHub issue related to custom converters](https://github.com/dotnet/corefx/issues/36639) +* [Source code for built-in converters](https://github.com/dotnet/runtime/tree/master/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/runtime/tree/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/) -* [GitHub issue related to custom converters](https://github.com/dotnet/corefx/issues/36639) +* [How to migrate from Newtonsoft.Json](system-text-json-migrate-from-newtonsoft-how-to.md) +* [System.Text.Json API reference](xref:System.Text.Json) + diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index 02b62108c1b7a..5569dc8071d51 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -712,7 +712,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 index f70cad5d9b312..714e358f1b3ca 100644 --- 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 @@ -514,8 +514,9 @@ For a code example, see [Use JsonDocument for access to data](system-text-json-h ## Additional resources +* * [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) * [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) diff --git a/docs/standard/serialization/system-text-json-overview.md b/docs/standard/serialization/system-text-json-overview.md index 9d116883587af..32314213a57f1 100644 --- a/docs/standard/serialization/system-text-json-overview.md +++ b/docs/standard/serialization/system-text-json-overview.md @@ -30,10 +30,13 @@ The library also provides classes for working with an in-memory document object ## 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/master/src/libraries/System.Text.Json) +* [System.Text.Json API reference](xref:System.Text.Json) + +* GitHub issues in the dotnet/corefx and dotnet/runtime repositories + * [Discussion about the development of System.Text.Json](https://github.com/dotnet/corefx/issues/33115) + * [System.Text.Json issues in dotnet/corefx](https://github.com/dotnet/corefx/issues?q=is%3Aopen+is%3Aissue+label%3Aarea-System.Text.Json) + * [System.Text.Json issues in dotnet/runtime](https://github.com/dotnet/runtime/issues?q=is%3Aopen+is%3Aissue+label%3Aarea-System.Text.Json) + From 163ed4eb6fc1797d670e44fde2efb266a5451f00 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 17 Dec 2019 13:29:24 -0800 Subject: [PATCH 18/74] rearrange several h2 sections --- ...ext-json-migrate-from-newtonsoft-how-to.md | 38 +++++++++---------- .../system-text-json-overview.md | 1 - 2 files changed, 19 insertions(+), 20 deletions(-) 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 index 714e358f1b3ca..abe0b37f151cc 100644 --- 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 @@ -21,7 +21,7 @@ This article shows how to migrate from [Newtonsoft.Json](https://www.newtonsoft. Most of this article is about how to use the API, but it also includes guidance on how to use the Document Object Model (DOM) and the and API. The article is organized into sections in the following order: * Differences in default `System.Text.Json.JsonSerializer` behavior compared to `Newtonsoft.Json`. -* Scenarios that `JsonSerializer` doesn't support, but workarounds might be feasible. [Go to the first of these sections.](#deserialize-inferred-types-to-object-properties) +* Scenarios that `JsonSerializer` doesn't support, but workarounds might be feasible. [Go to the first of these sections.](#specify-date-format) * Scenarios that `JsonSerializer` doesn't support, and workarounds are relatively difficult or impractical. [Go to the first of these sections.](#types-without-built-in-support). * [Utf8JsonReader and Utf8JsonWriter](#utf8jsonreader-and-utf8jsonwriter). * [JsonDocument](#jsondocument). @@ -40,10 +40,6 @@ During deserialization, `Newtonsoft.Json` ignores comments in the JSON by defaul During deserialization, `Newtonsoft.Json` ignores trailing commas by default. In some cases, it ignores multiple trailing commas (for example, `[{"Color":"Red"},{"Color":"Green"},,]`). The `System.Text.Json` default is to throw exceptions for trailing commas because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't include them. For information about how to allow trailing commas, 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. -## 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 Unicode code of the character.) `System.Text.Json` escapes more characters by default to provide defense-in-depth protections against cross-site scripting (XSS) or information disclosure attacks. `System.Text.Json` escapes all non-ASCII characters by default, so you don't need to do anything if you're using `StringEscapeHandling.EscapeNonAscii`. 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). - ## Converter registration precedence The `Newtonsoft.Json` registration precedence for custom converters is as follows: @@ -71,6 +67,24 @@ The difference here is that a custom converter in the `Converters` collection ov Other functions of the `Newtonsoft.Json` `[JsonProperty]` attribute have no equivalent attribute in `System.Text.Json`. For some of those functions, there are other ways to accomplish the same purpose, as detailed in the following sections of this article. +## 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 Unicode code of the character.) `System.Text.Json` escapes more characters by default to provide defense-in-depth protections against cross-site scripting (XSS) or information disclosure attacks. `System.Text.Json` escapes all non-ASCII characters by default, so you don't need to do anything if you're using `StringEscapeHandling.EscapeNonAscii`. 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). + +## Specify date format + +`Newtonsoft.Json` provides a `DateTimeZoneHandling` option that lets you specify the serialization format used for `DateTime` and `DateTimeOffset` properties. In `System.Text.Json`, the only format that has built-in support is ISO 8601-1:2019. 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) and issue [41456](https://github.com/dotnet/corefx/issues/41456) in the dotnet/corefx GitHub repository. + +## Quoted numbers + +`Newtonsoft.Json` can serialize or deserialize numbers in quotes. For example, it can accept: `{ "DegreesCelsius":"23" }` instead of `{ "DegreesCelsius":23 }`. To enable that behavior in `System.Text.Json`, implement a custom converter like the following example, which uses quotes for properties defined as `long`. + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/LongToStringConverter.cs)] + +[Register this custom converter](system-text-json-converters-how-to.md#register-a-custom-converter) by using an attribute on individual `long` properties or by adding the converter to the `Converters` collection. + +For more information, see issue [39473](https://github.com/dotnet/corefx/issues/39473) in the dotnet/corefx GitHub repository. + ## Deserialize inferred types to Object properties When deserializing JSON data to a property of type `Object`, `Newtonsoft.Json` infers the type of a property based on the JSON property value. For example, if a JSON property has "2020-01-01T05:40Z", the `Newtonsoft.Json` deserializer infers that it's a `DateTime` unless you specify `DateParseHandling.None`. When `System.Text.Json` deserializes to type `Object`, it always creates a `JsonElement` object. @@ -175,16 +189,6 @@ For more information, see the following issues in the dotnet/corefx GitHub repos * [38154](https://github.com/dotnet/corefx/issues/38154) New modifier is not hiding base property * [39905](https://github.com/dotnet/corefx/issues/39905) Allow custom converters for base-classes -## Quoted numbers - -`Newtonsoft.Json` can serialize or deserialize numbers in quotes. For example, it can accept: `{ "DegreesCelsius":"23" }` instead of `{ "DegreesCelsius":23 }`. To enable that behavior in `System.Text.Json`, implement a custom converter like the following example, which uses quotes for properties defined as `long`. - -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/LongToStringConverter.cs)] - -[Register this custom converter](system-text-json-converters-how-to.md#register-a-custom-converter) by using an attribute on individual `long` properties or by adding the converter to the `Converters` collection. - -For more information, see issue [39473](https://github.com/dotnet/corefx/issues/39473) in the dotnet/corefx GitHub repository. - ## Required properties During deserialization, `System.Text.Json` 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: @@ -294,10 +298,6 @@ For more information, see the following issues in the dotnet/corefx GitHub repos * [40600](https://github.com/dotnet/corefx/issues/40600) Ignore selected properties when null * [38878](https://github.com/dotnet/corefx/issues/38878) Ignore default values -## Specify date format - -`Newtonsoft.Json` provides a `DateTimeZoneHandling` option that lets you specify the serialization format used for `DateTime` and `DateTimeOffset` properties. In `System.Text.Json`, the only format that has built-in support is ISO 8601-1:2019. 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) and issue [41456](https://github.com/dotnet/corefx/issues/41456) in the dotnet/corefx GitHub repository. - ## Callbacks `Newtonsoft.Json` lets you execute custom code at several points in the serialization or deserialization process: diff --git a/docs/standard/serialization/system-text-json-overview.md b/docs/standard/serialization/system-text-json-overview.md index 32314213a57f1..2c88c5cfefd14 100644 --- a/docs/standard/serialization/system-text-json-overview.md +++ b/docs/standard/serialization/system-text-json-overview.md @@ -39,4 +39,3 @@ The library also provides classes for working with an in-memory document object * [Discussion about the development of System.Text.Json](https://github.com/dotnet/corefx/issues/33115) * [System.Text.Json issues in dotnet/corefx](https://github.com/dotnet/corefx/issues?q=is%3Aopen+is%3Aissue+label%3Aarea-System.Text.Json) * [System.Text.Json issues in dotnet/runtime](https://github.com/dotnet/runtime/issues?q=is%3Aopen+is%3Aissue+label%3Aarea-System.Text.Json) - From b5bd3e746b83e18e5e20f04ef4da938c573b8b71 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Thu, 19 Dec 2019 09:28:59 -0800 Subject: [PATCH 19/74] add (marshal/unmarshal) to headings --- .../serialization/system-text-json-converters-how-to.md | 2 +- docs/standard/serialization/system-text-json-how-to.md | 2 +- docs/standard/serialization/system-text-json-overview.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 3b679f22af186..15bdee71547df 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -11,7 +11,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). diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index 5569dc8071d51..b85ade84adf87 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -10,7 +10,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). diff --git a/docs/standard/serialization/system-text-json-overview.md b/docs/standard/serialization/system-text-json-overview.md index 2c88c5cfefd14..bf2ac5dbfbcb5 100644 --- a/docs/standard/serialization/system-text-json-overview.md +++ b/docs/standard/serialization/system-text-json-overview.md @@ -11,7 +11,7 @@ helpviewer_keywords: ms.assetid: 4d1111c0-9447-4231-a997-96a2b74b3453 --- -# 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). From 77712452d8c84ad5de2578c3879e23ec26362dbf Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Fri, 20 Dec 2019 14:37:38 -0800 Subject: [PATCH 20/74] update dates --- .../serialization/system-text-json-converters-how-to.md | 2 +- docs/standard/serialization/system-text-json-how-to.md | 2 +- .../system-text-json-migrate-from-newtonsoft-how-to.md | 2 +- docs/standard/serialization/system-text-json-overview.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) 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 15bdee71547df..b870ff626a560 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -2,7 +2,7 @@ title: "How to write custom converters for JSON serialization - .NET" author: tdykstra ms.author: tdykstra -ms.date: "10/16/2019" +ms.date: "12/20/2019" helpviewer_keywords: - "JSON serialization" - "serializing objects" diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index b85ade84adf87..add170ab9ebfd 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -2,7 +2,7 @@ title: "How to serialize and deserialize JSON using C# - .NET" author: tdykstra ms.author: tdykstra -ms.date: "09/16/2019" +ms.date: "12/20/2019" helpviewer_keywords: - "JSON serialization" - "serializing objects" 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 index abe0b37f151cc..8ec05f27b174e 100644 --- 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 @@ -2,7 +2,7 @@ title: "Migrate from Newtonsoft.Json to System.Text.Json - .NET" author: tdykstra ms.author: tdykstra -ms.date: "12/02/2019" +ms.date: "12/20/2019" helpviewer_keywords: - "JSON serialization" - "serializing objects" diff --git a/docs/standard/serialization/system-text-json-overview.md b/docs/standard/serialization/system-text-json-overview.md index bf2ac5dbfbcb5..8ad27e64bb238 100644 --- a/docs/standard/serialization/system-text-json-overview.md +++ b/docs/standard/serialization/system-text-json-overview.md @@ -2,7 +2,7 @@ title: "Serialize and deserialize JSON using C# - .NET" author: tdykstra ms.author: tdykstra -ms.date: "09/16/2019" +ms.date: "12/20/2019" helpviewer_keywords: - "JSON serialization" - "serializing objects" From a1eae47b71efb70c73073f77b198958e43148300 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 24 Dec 2019 13:02:25 -0800 Subject: [PATCH 21/74] ahson feedback, restore code to converters doc --- .../system-text-json-converters-how-to.md | 131 +++++++++++++++++- .../system-text-json-overview.md | 4 - 2 files changed, 124 insertions(+), 11 deletions(-) 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 b870ff626a560..1a0a6d02da98a 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -20,7 +20,11 @@ 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. For more information, see [How to migrate from Newtonsoft.Json to System.Text.Json](system-text-json-migrate-from-newtonsoft-how-to.md). +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). +* [Support Dictionary with non-string key](#support-dictionary-with-non-string-key). +* [Support polymorphic deserialization](#support-polymorphic-deserialization). ## Custom converter patterns @@ -52,6 +56,8 @@ The following code shows a custom converter that works with `Dictionary 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 [Polymorphic deserialization](system-text-json-migrate-from-newtonsoft-how-to.md#polymorphic-deserialization). +* 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/runtime/tree/master/src/libraries/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/f77914d4c9045a01b3a91b63c28805f24850c274/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/) as reference implementations for writing custom converters. ## Steps to follow the factory pattern @@ -160,11 +166,122 @@ If multiple custom converters for a type are registered in the `Converters` coll A built-in converter is chosen only if no applicable custom converter is registered. +## Converter samples for common scenarios + +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) +* [Support Dictionary with non-string key](#support-dictionary-with-non-string-key) +* [Support polymorphic deserialization](#support-polymorphic-deserialization) + +### 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`. + +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: + +* `true` and `false` to `Boolean` +* Numbers to `long` or `double` +* Dates to `DateTime` +* Strings to `string` +* Everything else to `JsonElement` + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/ObjectToInferredTypesConverter.cs)] + +The following code registers the converter: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/ConvertInferredTypesToObject.cs?name=SnippetRegister)] + +Here's an example type with `Object` properties: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecast.cs?name=SnippetWFWithObjectProperties)] + +The following example of JSON to deserialize contains values that will be deserialized as `DateTime`, `long`, and `string`: + +```json +{ + "Date": "2019-08-01T00:00:00-07:00", + "TemperatureCelsius": 25, + "Summary": "Hot", +} +``` + +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. + +### Support Dictionary with non-string key + +The built-in support for dictionary collections is for `Dictionary`. That is, the key must be a string. To support a dictionary with an integer or some other type as the key, a custom converter is required. + +The following code shows a custom converter that works with `Dictionary`: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/DictionaryTKeyEnumTValueConverter.cs)] + +The following code registers the converter: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/ConvertDictionaryTkeyEnumTValue.cs?name=SnippetRegister)] + +The converter can serialize and deserialize the `TemperatureRanges` property of the following class that uses the following `Enum`: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecast.cs?name=SnippetWFWithEnumDictionary)] + +The JSON output from serialization looks like the following example: + +```json +{ + "Date": "2019-08-01T00:00:00-07:00", + "TemperatureCelsius": 25, + "Summary": "Hot", + "TemperatureRanges": { + "Cold": 20, + "Hot": 40 + } +} +``` + +The [unit tests folder](https://github.com/dotnet/corefx/blob/f77914d4c9045a01b3a91b63c28805f24850c274/src/System.Text.Json/tests/Serialization/) in the `System.Text.Json.Serialization` namespace has more examples of custom converters that handle non-string-key dictionaries. + +### Support polymorphic deserialization + +[Polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes) doesn't require a custom converter, but deserialization does require a custom converter. + +Suppose, for example, you have a `Person` abstract base class, with `Employee` and `Customer` derived classes. Polymorphic deserialization means that at design time you can specify `Person` as the deserialization target, and `Customer` and `Employee` objects in the JSON are correctly deserialized at runtime. During deserialization, you have to find clues that identify the required type in the JSON. The kinds of clues available vary with each scenario. For example, a discriminator property might be available or you might have to rely on the presence or absence of a particular property. The current release of `System.Text.Json` doesn't provide attributes to specify how to handle polymorphic deserialization scenarios, so custom converters are required. + +The following code shows a base class, two derived classes, and a custom converter for them. The converter uses a discriminator property to do polymorphic deserialization. The type discriminator isn't in the class definitions but is created during serialization and is read during deserialization. + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/Person.cs?name=SnippetPerson)] + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/PersonConverterWithTypeDiscriminator.cs)] + +The following code registers the converter: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/ConvertPolymorphic.cs?name=SnippetRegister)] + +The converter can deserialize JSON that was created by using the same converter to serialize, for example: + +```json +[ + { + "TypeDiscriminator": 1, + "CreditLimit": 10000, + "Name": "John" + }, + { + "TypeDiscriminator": 2, + "OfficeNumber": "555-1234", + "Name": "Nancy" + } +] +``` + ## Other custom converter samples The [Migrate from Newtonsoft.Json to System.Text.Json](system-text-json-migrate-from-newtonsoft-how-to.md) article contains samples of custom converters. -The [unit tests folder](https://github.com/dotnet/runtime/blob/master/src/libraries/System.Text.Json/tests/Serialization/) in the `System.Text.Json.Serialization` source code includes other custom converter samples, such as: +The [unit tests folder](https://github.com/dotnet/runtime/blob/f77914d4c9045a01b3a91b63c28805f24850c274/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 * `Int32` converter that allows both string and number values on deserialize @@ -172,15 +289,15 @@ The [unit tests folder](https://github.com/dotnet/runtime/blob/master/src/librar * `List` converter that accepts external data * `Long[]` converter that works with a comma-delimited list of numbers -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/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters) to serve as a starting point for customization. +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/f77914d4c9045a01b3a91b63c28805f24850c274/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters) to serve as a starting point for customization. ## Additional resources -* [GitHub issue related to custom converters](https://github.com/dotnet/corefx/issues/36639) -* [Source code for built-in converters](https://github.com/dotnet/runtime/tree/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/) +* [Source code for built-in converters](https://github.com/dotnet/runtime/tree/f77914d4c9045a01b3a91b63c28805f24850c274/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) * [How to use System.Text.Json](system-text-json-how-to.md) * [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-overview.md b/docs/standard/serialization/system-text-json-overview.md index 8ad27e64bb238..73b968acc2e68 100644 --- a/docs/standard/serialization/system-text-json-overview.md +++ b/docs/standard/serialization/system-text-json-overview.md @@ -35,7 +35,3 @@ The library also provides classes for working with an in-memory document object * [System.Text.Json source code](https://github.com/dotnet/runtime/tree/master/src/libraries/System.Text.Json) * [System.Text.Json API reference](xref:System.Text.Json) -* GitHub issues in the dotnet/corefx and dotnet/runtime repositories - * [Discussion about the development of System.Text.Json](https://github.com/dotnet/corefx/issues/33115) - * [System.Text.Json issues in dotnet/corefx](https://github.com/dotnet/corefx/issues?q=is%3Aopen+is%3Aissue+label%3Aarea-System.Text.Json) - * [System.Text.Json issues in dotnet/runtime](https://github.com/dotnet/runtime/issues?q=is%3Aopen+is%3Aissue+label%3Aarea-System.Text.Json) From b023d847a1a2e353079e9d0d1825a071bab496bb Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 24 Dec 2019 13:54:29 -0800 Subject: [PATCH 22/74] move 3 converters back to converter doc --- ...ext-json-migrate-from-newtonsoft-how-to.md | 90 ++----------------- 1 file changed, 5 insertions(+), 85 deletions(-) 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 index 8ec05f27b174e..1142327bb8f81 100644 --- 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 @@ -89,99 +89,19 @@ For more information, see issue [39473](https://github.com/dotnet/corefx/issues/ When deserializing JSON data to a property of type `Object`, `Newtonsoft.Json` infers the type of a property based on the JSON property value. For example, if a JSON property has "2020-01-01T05:40Z", the `Newtonsoft.Json` deserializer infers that it's a `DateTime` unless you specify `DateParseHandling.None`. When `System.Text.Json` deserializes to type `Object`, it always creates a `JsonElement` object. -The `System.Text.Json` deserializer doesn't guess what type a given property value represents because 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`. - -If your scenario requires type inference for `Object` properties, you can implement a custom converter. The following sample code converts: - -* `true` and `false` to `Boolean` -* Numbers without a decimal to `long` -* Numbers with a decimal to `double` -* Dates to `DateTime` -* Strings to `string` -* Everything else to `JsonElement` - -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/ObjectToInferredTypesConverter.cs)] - -[Register this custom converter](system-text-json-converters-how-to.md#register-a-custom-converter) by adding it to the `Converters` collection or by using the `[JsonConvert]` attribute on a property. - -Here's an example type with `Object` properties: - -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecast.cs?name=SnippetWFWithObjectProperties)] - -The following example of JSON to deserialize contains values that will be deserialized as `DateTime`, `long`, and `string`: - -```json -{ - "Date": "2019-08-01T00:00:00-07:00", - "TemperatureCelsius": 25, - "Summary": "Hot", -} -``` - -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. For more information, see issue [38713](https://github.com/dotnet/corefx/issues/38713) in the dotnet/corefx GitHub repository. +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). See also issue [38713](https://github.com/dotnet/corefx/issues/38713) in the dotnet/corefx GitHub repository. ## Dictionary with non-string key -`Newtonsoft.Json` supports collections of type `Dictionary`. The built-in support for dictionary collections in `System.Text.Json` 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, a custom converter is required. - -The following code shows a custom converter that works with `Dictionary`: - -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/DictionaryTKeyEnumTValueConverter.cs)] - -[Register this custom converter](system-text-json-converters-how-to.md#register-a-custom-converter) by adding it to the `Converters` collection or by using the `[JsonConvert]` attribute on a property. - -The converter can serialize and deserialize the `TemperatureRanges` property of the following class that uses the following `Enum`: - -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecast.cs?name=SnippetWFWithEnumDictionary)] +`Newtonsoft.Json` supports collections of type `Dictionary`. The built-in support for dictionary collections in `System.Text.Json` is limited to `Dictionary`. That is, the key must be a string. -The JSON output from serialization looks like the following example: - -```json -{ - "Date": "2019-08-01T00:00:00-07:00", - "TemperatureCelsius": 25, - "Summary": "Hot", - "TemperatureRanges": { - "Cold": 20, - "Hot": 40 - } -} -``` - -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 non-string-key dictionaries. For more information, see issue [40120](https://github.com/dotnet/corefx/issues/40120) in the dotnet/corefx GitHub repository. +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). See also issue [40120](https://github.com/dotnet/corefx/issues/40120) in the dotnet/corefx GitHub repository. ## Polymorphic deserialization -`Newtonsoft.Json` can do polymorphic serialization and deserialization. Suppose, for example, you have a `Person` abstract base class, with `Employee` and `Customer` derived classes. Polymorphic deserialization means that at design time you can specify `Person` as the deserialization target, and `Customer` and `Employee` objects in the JSON are correctly deserialized at runtime. To do that, the deserializer has to find clues that identify the required type in the JSON. For example, a discriminator property might be available or you might have to rely on the presence or absence of a particular property. `Newtonsoft.Json` provides attributes that specify how to handle polymorphic deserialization scenarios. `System.Text.Json` doesn't provide such attributes. If there's no need for polymorphic deserialization, `System.Text.Json` can do [polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes). But the ability to do polymorphic deserialization or convert the same data in both directions requires a custom converter. - -The following code shows a base class, two derived classes, and a custom converter for them. The converter uses a discriminator property to do polymorphic deserialization. The type discriminator isn't in the class definitions but is created during serialization and is read during deserialization. - -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/Person.cs?name=SnippetPerson)] - -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/PersonConverterWithTypeDiscriminator.cs)] +`Newtonsoft.Json` provides attributes that specify how to handle polymorphic deserialization scenarios. `System.Text.Json` doesn't provide such attributes. `System.Text.Json` can do [polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes) but not polymorphic deserialization or conversion of the same data in both directions. -[Register this custom converter](system-text-json-converters-how-to.md#register-a-custom-converter) by adding it to the `Converters` collection. - -The converter can deserialize JSON that was created by using the same converter to serialize, for example: - -```json -[ - { - "TypeDiscriminator": 1, - "CreditLimit": 10000, - "Name": "John" - }, - { - "TypeDiscriminator": 2, - "OfficeNumber": "555-1234", - "Name": "Nancy" - } -] -``` - -For more information, see the following issues in the dotnet/corefx GitHub repository: +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). See also the following issues in the dotnet/corefx GitHub repository: * [38650](https://github.com/dotnet/corefx/issues/38650) Support polymorphic serialization * [39031](https://github.com/dotnet/corefx/issues/39031) Support polymorphic deserialization From 55d99cc34c95222e4f895b5bea6a4502a0267788 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 24 Dec 2019 15:39:59 -0800 Subject: [PATCH 23/74] additional note from comments in 36639 --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 1142327bb8f81..d31f865e7d9fb 100644 --- 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 @@ -130,7 +130,7 @@ To make deserialization fail if no `Date` property is in the JSON, implement a c [Register this custom converter](system-text-json-converters-how-to.md#register-a-custom-converter) by using an attribute on the POCO class or by adding the converter to the `Converters` collection. -If you follow this pattern, 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 custom converter calls into itself, making an infinite loop that results in a stack overflow exception. +If you follow this pattern, 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 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. This is a simplified example. More complex code would be required if you need to handle attributes (such as `[JsonIgnore]`) or options (such as custom encoders). From a78c5ac9cd3a9713303e4cdb31a4832066837ebe Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Thu, 26 Dec 2019 12:35:17 -0800 Subject: [PATCH 24/74] minor clarification --- .../serialization/system-text-json-converters-how-to.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 1a0a6d02da98a..05fb334d5fcad 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -183,7 +183,8 @@ Type inference can be inaccurate. If the deserializer parses a JSON number that 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` From 9c331ff0b7f941330cc675d5f301734a5f6423c0 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Thu, 26 Dec 2019 16:30:26 -0800 Subject: [PATCH 25/74] remove links to issues --- .../serialization/system-text-json-how-to.md | 10 +-- ...ext-json-migrate-from-newtonsoft-how-to.md | 69 ++++++------------- 2 files changed, 26 insertions(+), 53 deletions(-) diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index add170ab9ebfd..3f8f16ed41059 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -106,7 +106,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.on GitHub. * Currently, fields are excluded. Supported types include: @@ -115,7 +115,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. * * * @@ -151,13 +151,13 @@ To deserialize from UTF-8, call a `. The built-in support for dictionary collections in `System.Text.Json` 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). See also issue [40120](https://github.com/dotnet/corefx/issues/40120) in the dotnet/corefx GitHub repository. +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 deserialization `Newtonsoft.Json` provides attributes that specify how to handle polymorphic deserialization scenarios. `System.Text.Json` doesn't provide such attributes. `System.Text.Json` can do [polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes) but not polymorphic deserialization or conversion of the same data in both directions. -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). See also the following issues in the dotnet/corefx GitHub repository: - -* [38650](https://github.com/dotnet/corefx/issues/38650) Support polymorphic serialization -* [39031](https://github.com/dotnet/corefx/issues/39031) Support polymorphic deserialization -* [41758](https://github.com/dotnet/corefx/issues/41758) System.Text.Json ignores JsonPropertyName on base class -* [38154](https://github.com/dotnet/corefx/issues/38154) New modifier is not hiding base property -* [39905](https://github.com/dotnet/corefx/issues/39905) Allow custom converters for base-classes +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 @@ -134,8 +126,6 @@ If you follow this pattern, don't pass in the options object when recursively ca This is a simplified example. More complex code would be required if you need to handle attributes (such as `[JsonIgnore]`) or options (such as custom encoders). -For more information, see issue [38492](https://github.com/dotnet/corefx/issues/38492) in the dotnet/corefx GitHub repository. - ## Deserialize null to non-nullable type `Newtonsoft.Json` doesn't throw an exception in the following scenario: @@ -153,8 +143,6 @@ Another workaround is to make a converter for the type, such as the following ex [Register this custom converter](system-text-json-converters-how-to.md#register-a-custom-converter) by using an attribute on the property or by adding the converter to the `Converters` collection. -For more information, see issue [40922](https://github.com/dotnet/corefx/issues/40922) in the dotnet/corefx GitHub repository. - ## Deserialize to immutable classes and structs `Newtonsoft.Json` can deserialize to immutable classes and structs because it can use constructors that have parameters. `System.Text.Json` supports only parameterless constructors. As a workaround, you can call a constructor with parameters in a custom converter. @@ -171,8 +159,6 @@ And here's a converter that serializes and deserializes this struct: 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/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterKeyValuePair.cs). -For more information, see issue [38569](https://github.com/dotnet/corefx/issues/38569) in the dotnet/corefx GitHub repository. - ## Specify constructor to use The `Newtonsoft.Json` `[JsonConstructor]` attribute lets you specify which constructor to call when deserializing to a POCO. `System.Text.Json` 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). @@ -212,12 +198,6 @@ This approach requires complex code if: * The POCO includes complex properties. * You need to handle attributes such as `[JsonIgnore]` or options such as custom encoders. -For more information, see the following issues in the dotnet/corefx GitHub repository: - -* [42001](https://github.com/dotnet/corefx/issues/42001) Equivalent of DefaultContractResolver -* [40600](https://github.com/dotnet/corefx/issues/40600) Ignore selected properties when null -* [38878](https://github.com/dotnet/corefx/issues/38878) Ignore default values - ## Callbacks `Newtonsoft.Json` lets you execute custom code at several points in the serialization or deserialization process: @@ -238,28 +218,26 @@ If you use a custom converter that follows this example: * 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. -For more information, see issue [36639](https://github.com/dotnet/corefx/issues/36639) in the dotnet/corefx GitHub repository. - ## Types without built-in support -`System.Text.Json` doesn't provide built-in support for the following types. The list includes links to the issues that track the request for support: +`System.Text.Json` doesn't provide built-in support for the following types: -* and related types. [38712](https://github.com/dotnet/corefx/issues/38712) -* 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). [38348](https://github.com/dotnet/corefx/issues/38348) -* Collection types in the namespace. [40370](https://github.com/dotnet/corefx/issues/40370) -* . [38007](https://github.com/dotnet/corefx/issues/38007) -* . [41348](https://github.com/dotnet/corefx/issues/41348) -* . [33458](https://github.com/dotnet/corefx/issues/33458) -* . [38641](https://github.com/dotnet/corefx/issues/38641) -* . [418](https://github.com/dotnet/runtime/issues/418) +* 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 +* +* +* +* +* ## Fields -`Newtonsoft.Json` can serialize and deserialize fields as well as properties. `System.Text.Json` only works with properties. For more information, see issue [36505](https://github.com/dotnet/corefx/issues/36505) in the dotnet/corefx GitHub repository. +`Newtonsoft.Json` can serialize and deserialize fields as well as properties. `System.Text.Json` only works with properties. ## Private setters -`Newtonsoft.Json` can use private property setters. `System.Text.Json` supports only public setters. For more information, see issue [38163](https://github.com/dotnet/corefx/issues/38163) in the dotnet/corefx GitHub repository. +`Newtonsoft.Json` can use private property setters. `System.Text.Json` supports only public setters. ## Preserve object references and handle loops @@ -272,36 +250,31 @@ By default, `Newtonsoft.Json` serializes by value. For example, if an object con `Newtonsoft.Json` also has a `ReferenceLoopHandling` setting that lets you ignore circular references rather than throw an exception. -`System.Text.Json` supports only serialization by value. For more information, see the following issues in the dotnet/corefx GitHub repository: - -* [37786](https://github.com/dotnet/corefx/issues/37786) Support for object references -* [41002](https://github.com/dotnet/corefx/issues/41002) Circular reference handling +`System.Text.Json` supports only serialization by value. ## System.Runtime.Serialization attributes `System.Text.Json` doesn't support attributes from the `System.Runtime.Serialization` namespace, such as `DataMemberAttribute` and `IgnoreDataMemberAttribute`. -For more information, see issue [38758](https://github.com/dotnet/corefx/issues/38758) in the dotnet/corefx GitHub repository. - ## Octal numbers `Newtonsoft.Json` treats numbers with a leading zero as octal numbers. `System.Text.Json` doesn't allow leading zeroes because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't allow them. ## Type name handling -`Newtonsoft.Json` has a `TypeNameHandling` setting that adds type name metadata to the JSON while serializing, and it uses the metadata while deserializing. `System.Text.Json` lacks this feature. For more information, see issue [39031](https://github.com/dotnet/corefx/issues/39031) in the dotnet/corefx GitHub repository. +`Newtonsoft.Json` has a `TypeNameHandling` setting that adds type name metadata to the JSON while serializing, and it uses the metadata while deserializing. `System.Text.Json` lacks this feature. ## Populate existing objects -The `Newtonsoft.Json` `JsonConvert.PopulateObject` method deserializes a JSON document to an existing instance of a class, instead of creating a new instance. `System.Text.Json` always creates a new instance of the target type by using the default parameterless constructor. For more information, see issue [37627](https://github.com/dotnet/corefx/issues/37627) in the dotnet/corefx GitHub repository. +The `Newtonsoft.Json` `JsonConvert.PopulateObject` method deserializes a JSON document to an existing instance of a class, instead of creating a new instance. `System.Text.Json` always creates a new instance of the target type by using the default parameterless constructor. ## Reuse rather than replace properties -The `Newtonsoft.Json` `ObjetCreationHandling` setting lets you specify that objects in properties should be reused rather than replaced during deserialization. `System.Text.Json` always replaces objects in properties. For more information, see issue [42515](https://github.com/dotnet/corefx/issues/42515) in the dotnet/corefx GitHub repository. +The `Newtonsoft.Json` `ObjetCreationHandling` setting lets you specify that objects in properties should be reused rather than replaced during deserialization. `System.Text.Json` always replaces objects in properties. ## Add to collections without setters -During deserialization, `Newtonsoft.Json` adds objects to a collection even if the property has no setter. `System.Text.Json` ignores properties that don't have setters. For more information, see issue [39477](https://github.com/dotnet/corefx/issues/39477) in the dotnet/corefx GitHub repository. +During deserialization, `Newtonsoft.Json` adds objects to a collection even if the property has no setter. `System.Text.Json` ignores properties that don't have setters. ## MissingMemberHandling @@ -417,7 +390,7 @@ If you need to continue to use `Newtonsoft.Json` for certain target frameworks, Since the `System.Text.Json` DOM can't add, remove, or modify JSON elements. If your scenario currently uses a writable DOM, one of the following workarounds might be feasible: * To build a `JsonDocument` from scratch, write 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`. For more information, see issue [38589](https://github.com/dotnet/corefx/issues/38589) and issue [39922](https://github.com/dotnet/corefx/issues/39922) in the dotnet/corefx GitHub repository. +* 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`. ### JsonElement From 618aca8addb310432cc60bfc0b4080a00982a43a Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Thu, 26 Dec 2019 16:33:32 -0800 Subject: [PATCH 26/74] add links to s.t.j.serialization --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 1 + docs/standard/serialization/system-text-json-overview.md | 1 + 2 files changed, 2 insertions(+) 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 index cfd25422aaffb..343f83c2ea132 100644 --- 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 @@ -413,3 +413,4 @@ For a code example, see [Use JsonDocument for access to data](system-text-json-h * [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 73b968acc2e68..54d4aec7f40b2 100644 --- a/docs/standard/serialization/system-text-json-overview.md +++ b/docs/standard/serialization/system-text-json-overview.md @@ -34,4 +34,5 @@ The library also provides classes for working with an in-memory document object * [How to write converters](system-text-json-converters-how-to.md) * [System.Text.Json source code](https://github.com/dotnet/runtime/tree/master/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) From 84a65bc7fa1166e3e296f87570f943f342cf6b1f Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Thu, 26 Dec 2019 17:02:36 -0800 Subject: [PATCH 27/74] remove extraneous words --- docs/standard/serialization/system-text-json-how-to.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index 3f8f16ed41059..5b0604460bbcc 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -106,7 +106,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.on GitHub. +* Circular references are detected and exceptions thrown. * Currently, fields are excluded. Supported types include: From e4a27a1fff22aa7defe1f989c951fb6f269d11fc Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Thu, 26 Dec 2019 17:03:55 -0800 Subject: [PATCH 28/74] remove extraneous words --- docs/standard/serialization/system-text-json-how-to.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index 5b0604460bbcc..9efd1f9928a5c 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -151,7 +151,7 @@ To deserialize from UTF-8, call a Date: Thu, 26 Dec 2019 18:35:21 -0800 Subject: [PATCH 29/74] 4.6.1 --> 4.7.2 --- docs/standard/serialization/system-text-json-overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/standard/serialization/system-text-json-overview.md b/docs/standard/serialization/system-text-json-overview.md index 54d4aec7f40b2..ddcb768d0f0ad 100644 --- a/docs/standard/serialization/system-text-json-overview.md +++ b/docs/standard/serialization/system-text-json-overview.md @@ -24,7 +24,7 @@ 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 From 2feef0682f9cda54fe8146800cbc14d8b36c5379 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Thu, 26 Dec 2019 19:09:20 -0800 Subject: [PATCH 30/74] Update docs/standard/serialization/system-text-json-converters-how-to.md Co-Authored-By: Ahson Khan --- .../serialization/system-text-json-converters-how-to.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 05fb334d5fcad..6f42d7048b9d4 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -280,7 +280,7 @@ The converter can deserialize JSON that was created by using the same converter ## Other custom converter samples -The [Migrate from Newtonsoft.Json to System.Text.Json](system-text-json-migrate-from-newtonsoft-how-to.md) article contains samples of custom converters. +The [Migrate from Newtonsoft.Json to System.Text.Json](system-text-json-migrate-from-newtonsoft-how-to.md) article contains additional samples of custom converters. The [unit tests folder](https://github.com/dotnet/runtime/blob/f77914d4c9045a01b3a91b63c28805f24850c274/src/libraries/System.Text.Json/tests/Serialization/) in the `System.Text.Json.Serialization` source code includes other custom converter samples, such as: From 99619d12a87ee46d34e773adb830dc8281283854 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Thu, 26 Dec 2019 20:47:26 -0800 Subject: [PATCH 31/74] ahson feedback section 1 --- ...ext-json-migrate-from-newtonsoft-how-to.md | 170 ++++++++++-------- 1 file changed, 96 insertions(+), 74 deletions(-) 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 index 343f83c2ea132..2303499cd57b4 100644 --- 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 @@ -14,33 +14,37 @@ helpviewer_keywords: This article shows how to migrate from [Newtonsoft.Json](https://www.newtonsoft.com/json) to [System.Text.Json](system-text-json-overview.md). - `System.Text.Json` focuses primarily on performance, security, and standards compliance. It lacks built-in features to handle some common scenarios, and some default behaviors differ from `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 that has no workaround, consider delaying your migration to `System.Text.Json`. +`System.Text.Json` focuses primarily on performance, security, and standards compliance. It lacks built-in features to handle some common scenarios, and some default behaviors differ from `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 that has no workaround, consider delaying your migration to `System.Text.Json`. Most of this article is about how to use the API, but it also includes guidance on how to use the Document Object Model (DOM) and the and API. The article is organized into sections in the following order: -* Differences in default `System.Text.Json.JsonSerializer` behavior compared to `Newtonsoft.Json`. -* Scenarios that `JsonSerializer` doesn't support, but workarounds might be feasible. [Go to the first of these sections.](#specify-date-format) -* Scenarios that `JsonSerializer` doesn't support, and workarounds are relatively difficult or impractical. [Go to the first of these sections.](#types-without-built-in-support). -* [Utf8JsonReader and Utf8JsonWriter](#utf8jsonreader-and-utf8jsonwriter). +* Differences in **default** `System.Text.Json.JsonSerializer` behavior compared to `Newtonsoft.Json`. +* [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](#jsondocument). +* [Utf8JsonReader and Utf8JsonWriter](#utf8jsonreader-and-utf8jsonwriter). + +## Differences in default behavior -## Case-insensitive deserialization +`System.Text.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`. + +### Case-insensitive deserialization During deserialization, `Newtonsoft.Json` does case-insensitive property name matching by default. The `System.Text.Json` default is case-sensitive, which gives better performance. 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 case-insensitive setting when it uses `System.Text.Json`. -## Comments +### Comments During deserialization, `Newtonsoft.Json` ignores comments in the JSON by default. The `System.Text.Json` 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 +### Trailing commas -During deserialization, `Newtonsoft.Json` ignores trailing commas by default. In some cases, it ignores multiple trailing commas (for example, `[{"Color":"Red"},{"Color":"Green"},,]`). The `System.Text.Json` default is to throw exceptions for trailing commas because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't include them. For information about how to allow trailing commas, 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. +During deserialization, `Newtonsoft.Json` ignores trailing commas by default. It also ignores multiple trailing commas (for example, `[{"Color":"Red"},{"Color":"Green"},,]`). The `System.Text.Json` default is to throw exceptions for trailing commas because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't include them. For information about how to allow trailing commas, 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. -## Converter registration precedence +### Converter registration precedence The `Newtonsoft.Json` registration precedence for custom converters is as follows: @@ -58,24 +62,35 @@ The `System.Text.Json` registration precedence for custom converters is differen 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. -## `Newtonsoft.Json` [JsonProperty] attribute +### 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 `\"`). `System.Text.Json` 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). -`Newtonsoft.Json` has a `[JsonProperty]` attribute that is used for a variety of functions. `System.Text.Json` has single-purpose attributes instead of a multi-purpose attribute. The following attributes serve purposes similar to some of the `Newtonsoft.Json` attribute functions: +### Deserialization of Object properties + +When `Newtonsoft.Json` deserializes to `Object` properties in POCOs or in dictionaries of type `Dictionary`, it: + +* "Guesses" the type of "primitive" values in the JSON and stores `string`/`long`/`double`/`boolean` as a boxed object. +* Stores "complex" values as `JObject`. +* Stores `null` when the payload has "null". + +`System.Text.Json` stores a boxed `JsonElement` for "primitive" and "complex" values within the System.Object property or dictionary value. It stores `null` when the payload has "null" 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). -* [[JsonPropertyName]](system-text-json-how-to.md#customize-individual-property-names) -* [[JsonConverter]](system-text-json-converters-how-to.md#register-a-custom-converter) +## Maximum depth -Other functions of the `Newtonsoft.Json` `[JsonProperty]` attribute have no equivalent attribute in `System.Text.Json`. For some of those functions, there are other ways to accomplish the same purpose, as detailed in the following sections of this article. +`Newtonsoft.Json` doesn't have a maximum depth limit. For `System.Text.Json` there's a default limit of 64, and it's configurable by setting (xref:System.Text.Json.JsonSerializerOptions.MaxDepth?displayProperty=nameWithType). -## Character escaping +## Scenarios using JsonSerializer that require workarounds -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 Unicode code of the character.) `System.Text.Json` escapes more characters by default to provide defense-in-depth protections against cross-site scripting (XSS) or information disclosure attacks. `System.Text.Json` escapes all non-ASCII characters by default, so you don't need to do anything if you're using `StringEscapeHandling.EscapeNonAscii`. 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). +The following scenarios aren't supported by built-in functionality, but sample code is provided for workarounds. -## Specify date format +### Specify date format `Newtonsoft.Json` provides a `DateTimeZoneHandling` option that lets you specify the serialization format used for `DateTime` and `DateTimeOffset` properties. In `System.Text.Json`, the only format that has built-in support is ISO 8601-1:2019. 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 +### Quoted numbers `Newtonsoft.Json` can serialize or deserialize numbers in quotes. For example, it can accept: `{ "DegreesCelsius":"23" }` instead of `{ "DegreesCelsius":23 }`. To enable that behavior in `System.Text.Json`, implement a custom converter like the following example, which uses quotes for properties defined as `long`. @@ -83,25 +98,19 @@ During serialization, `Newtonsoft.Json` is relatively permissive about letting c [Register this custom converter](system-text-json-converters-how-to.md#register-a-custom-converter) by using an attribute on individual `long` properties or by adding the converter to the `Converters` collection. -## Deserialize inferred types to Object properties - -When deserializing JSON data to a property of type `Object`, `Newtonsoft.Json` infers the type of a property based on the JSON property value. For example, if a JSON property has "2020-01-01T05:40Z", the `Newtonsoft.Json` deserializer infers that it's a `DateTime` unless you specify `DateParseHandling.None`. When `System.Text.Json` deserializes to type `Object`, it always creates a `JsonElement` object. - -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). - -## Dictionary with non-string key +### Dictionary with non-string key `Newtonsoft.Json` supports collections of type `Dictionary`. The built-in support for dictionary collections in `System.Text.Json` 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 deserialization +### Polymorphic deserialization `Newtonsoft.Json` provides attributes that specify how to handle polymorphic deserialization scenarios. `System.Text.Json` doesn't provide such attributes. `System.Text.Json` can do [polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes) but not polymorphic deserialization or conversion of the same data in both directions. 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 +### Required properties During deserialization, `System.Text.Json` 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: @@ -126,7 +135,7 @@ If you follow this pattern, don't pass in the options object when recursively ca This is a simplified example. More complex code would be required if you need to handle attributes (such as `[JsonIgnore]`) or options (such as custom encoders). -## Deserialize null to non-nullable type +### Deserialize null to non-nullable type `Newtonsoft.Json` doesn't throw an exception in the following scenario: @@ -143,7 +152,7 @@ Another workaround is to make a converter for the type, such as the following ex [Register this custom converter](system-text-json-converters-how-to.md#register-a-custom-converter) by using an attribute on the property or by adding the converter to the `Converters` collection. -## Deserialize to immutable classes and structs +### Deserialize to immutable classes and structs `Newtonsoft.Json` can deserialize to immutable classes and structs because it can use constructors that have parameters. `System.Text.Json` supports only parameterless constructors. As a workaround, you can call a constructor with parameters in a custom converter. @@ -159,11 +168,11 @@ And here's a converter that serializes and deserializes this struct: 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/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterKeyValuePair.cs). -## Specify constructor to use +### Specify constructor to use The `Newtonsoft.Json` `[JsonConstructor]` attribute lets you specify which constructor to call when deserializing to a POCO. `System.Text.Json` 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 +### Conditionally ignore a property `Newtonsoft.Json` has several ways to conditionally ignore a property on serialization or deserialization: @@ -198,7 +207,7 @@ This approach requires complex code if: * The POCO includes complex properties. * You need to handle attributes such as `[JsonIgnore]` or options such as custom encoders. -## Callbacks +### Callbacks `Newtonsoft.Json` lets you execute custom code at several points in the serialization or deserialization process: @@ -218,7 +227,11 @@ If you use a custom converter that follows this example: * 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. -## Types without built-in support +## Scenarios that JsonSerializer currently doesn't support + +Workarounds may be possible for some of the following scenarios, but they would be relatively difficult or impractical to implement. + +### Types without built-in support `System.Text.Json` doesn't provide built-in support for the following types: @@ -231,15 +244,15 @@ If you use a custom converter that follows this example: * * -## Fields +### Fields `Newtonsoft.Json` can serialize and deserialize fields as well as properties. `System.Text.Json` only works with properties. -## Private setters +### Private setters `Newtonsoft.Json` can use private property setters. `System.Text.Json` supports only public setters. -## Preserve object references and handle loops +### 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. @@ -252,38 +265,66 @@ By default, `Newtonsoft.Json` serializes by value. For example, if an object con `System.Text.Json` supports only serialization by value. -## System.Runtime.Serialization attributes +### System.Runtime.Serialization attributes `System.Text.Json` doesn't support attributes from the `System.Runtime.Serialization` namespace, such as `DataMemberAttribute` and `IgnoreDataMemberAttribute`. -## Octal numbers +### Octal numbers `Newtonsoft.Json` treats numbers with a leading zero as octal numbers. `System.Text.Json` doesn't allow leading zeroes because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't allow them. -## Type name handling +### Type name handling `Newtonsoft.Json` has a `TypeNameHandling` setting that adds type name metadata to the JSON while serializing, and it uses the metadata while deserializing. `System.Text.Json` lacks this feature. -## Populate existing objects +### Populate existing objects The `Newtonsoft.Json` `JsonConvert.PopulateObject` method deserializes a JSON document to an existing instance of a class, instead of creating a new instance. `System.Text.Json` always creates a new instance of the target type by using the default parameterless constructor. -## Reuse rather than replace properties +### Reuse rather than replace properties The `Newtonsoft.Json` `ObjetCreationHandling` setting lets you specify that objects in properties should be reused rather than replaced during deserialization. `System.Text.Json` always replaces objects in properties. -## Add to collections without setters +### Add to collections without setters During deserialization, `Newtonsoft.Json` adds objects to a collection even if the property has no setter. `System.Text.Json` ignores properties that don't have setters. -## MissingMemberHandling +### MissingMemberHandling `Newtonsoft.Json` can be configured to throw exceptions during deserialization if the JSON includes properties that are missing in the target type. `System.Text.Json` 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 +### TraceWriter `Newtonsoft.Json` lets you debug by using a `TraceWriter` to view logs that are generated by serialization or deserialization. `System.Text.Json` doesn't do logging. +## JsonDocument + + provides the ability to build a read-only Document Object Model (DOM). 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. + +### IDisposable + +`JsonDocument` builds an in-memory view of the data into a pooled buffer. Therefore, unlike `Newtonsoft.Json` `JObject` or `JArray`, the `JsonDocument` type implements `IDisposable` and needs to be used inside a using block. + +### Read-only + +Since the `System.Text.Json` DOM can't add, remove, or modify JSON elements. If your scenario currently uses a writable DOM, one of the following workarounds might be feasible: + +* To build a `JsonDocument` from scratch, write 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`. + +### JsonElement + +`JsonDocument` exposes the `RootElement` as a property of type , which is the type that encompasses any JSON element. `Newtonsoft.Json` uses dedicated 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. + +### Search a JsonDocument + +Searches that use `Newtonsoft.Json` `JObject` or `JArray` tend to be relatively fast because they're lookups in some dictionary. By comparison, a sequential search through JSON elements stored as `JsonElement` is relatively slow. `System.Text.Json` is designed to minimize initial parse time rather than look-up 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 of every `JsonElement`. 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. + +For a code example, see [Use JsonDocument for access to data](system-text-json-how-to.md#use-jsondocument-for-access-to-data). + ## Utf8JsonReader and Utf8JsonWriter 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. @@ -318,6 +359,15 @@ while (reader.Read()) } ``` +### WRiteRawValue + +The `Newtonsoft.Json` `WriteRawValue` method writes raw JSON where a value is expected. `System.Text.Json` has no direct equivalent, but here's a workaround: + +```csharp +using JsonDocument doc = JsonDocument.Parse(string); +doc.WriteTo(writer); +``` + ### Read and write with UTF-8 text To achieve the best possible performance while using the `Utf8JsonReader` and `Utf8JsonWriter`, read and write JSON payloads already encoded as UTF-8 text rather than as UTF-16 strings. For example, if you're writing string literals, consider caching them as static byte arrays, and write those instead. For a code example, see [Filter data using Utf8JsonReader](system-text-json-how-to.md#filter-data-using-utf8jsonreader). @@ -377,35 +427,7 @@ If you need to continue to use `Newtonsoft.Json` for certain target frameworks, * [UnifiedJsonWriter.JsonTextWriter.cs](https://github.com/dotnet/runtime/blob/35fe82c2e90fa345d0b6ad243c14da193fb123fd/src/installer/managed/Microsoft.Extensions.DependencyModel/UnifiedJsonWriter.JsonTextWriter.cs) * [UnifiedJsonWriter.Utf8JsonWriter.cs](https://github.com/dotnet/runtime/blob/35fe82c2e90fa345d0b6ad243c14da193fb123fd/src/installer/managed/Microsoft.Extensions.DependencyModel/UnifiedJsonWriter.Utf8JsonWriter.cs) -## JsonDocument - - provides the ability to build a read-only Document Object Model (DOM). 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. - -### IDisposable - -`JsonDocument` builds an in-memory view of the data into a pooled buffer. Therefore, unlike `Newtonsoft.Json` `JObject` or `JArray`, the `JsonDocument` type implements `IDisposable` and needs to be used inside a using block. - -### Read-only - -Since the `System.Text.Json` DOM can't add, remove, or modify JSON elements. If your scenario currently uses a writable DOM, one of the following workarounds might be feasible: - -* To build a `JsonDocument` from scratch, write 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`. - -### JsonElement - -`JsonDocument` exposes the `RootElement` as a property of type , which is the type that encompasses any JSON element. `Newtonsoft.Json` uses dedicated 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. - -### Search a JsonDocument - -Searches that use `Newtonsoft.Json` `JObject` or `JArray` tend to be relatively fast because they're lookups in some dictionary. By comparison, a sequential search through JSON elements stored as `JsonElement` is relatively slow. `System.Text.Json` is designed to minimize initial parse time rather than look-up 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 of every `JsonElement`. 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. - -For a code example, see [Use JsonDocument for access to data](system-text-json-how-to.md#use-jsondocument-for-access-to-data). - -## Additional resources +### Additional resources * * [System.Text.Json overview](system-text-json-overview.md) From ec3d07cccabe2951d3f0ad19780727a99ebeac15 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Thu, 26 Dec 2019 21:12:28 -0800 Subject: [PATCH 32/74] fix h2->h3, tweak heading text --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index 2303499cd57b4..be276c196ad47 100644 --- 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 @@ -20,7 +20,7 @@ This article shows how to migrate from [Newtonsoft.Json](https://www.newtonsoft. Most of this article is about how to use the API, but it also includes guidance on how to use the Document Object Model (DOM) and the and API. The article is organized into sections in the following order: -* Differences in **default** `System.Text.Json.JsonSerializer` behavior compared to `Newtonsoft.Json`. +* [Differences in **default** JsonSerializer behavior compared to Newtonsoft.Json](#differences-in-default-behavior). * [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](#jsondocument). @@ -78,7 +78,7 @@ When `Newtonsoft.Json` deserializes to `Object` properties in POCOs or in dictio 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 +### Maximum depth `Newtonsoft.Json` doesn't have a maximum depth limit. For `System.Text.Json` there's a default limit of 64, and it's configurable by setting (xref:System.Text.Json.JsonSerializerOptions.MaxDepth?displayProperty=nameWithType). From 1919f9d72969ce204ed27f4a6725f595a82955e0 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Fri, 27 Dec 2019 11:02:04 -0800 Subject: [PATCH 33/74] layomi feedback --- ...ext-json-migrate-from-newtonsoft-how-to.md | 78 ++++++++++++------- 1 file changed, 49 insertions(+), 29 deletions(-) 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 index be276c196ad47..fecbf78bdd9a5 100644 --- 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 @@ -24,11 +24,12 @@ Most of this article is about how to use the 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. @@ -70,7 +71,7 @@ During serialization, `Newtonsoft.Json` is relatively permissive about letting c When `Newtonsoft.Json` deserializes to `Object` properties in POCOs or in dictionaries of type `Dictionary`, it: -* "Guesses" the type of "primitive" values in the JSON and stores `string`/`long`/`double`/`boolean` as a boxed object. +* "Guesses" the type of "primitive" values in the JSON and stores `string`/`long`/`double`/`boolean`/`DateTime` as a boxed object. * Stores "complex" values as `JObject`. * Stores `null` when the payload has "null". @@ -244,6 +245,10 @@ Workarounds may be possible for some of the following scenarios, but they would * * +Custom converters for some of these types would not necessarily be complex. Here's an example of a `DBNull` converter that just converts `DBNull` to `null`: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/DBNullConverter.cs)] + ### Fields `Newtonsoft.Json` can serialize and deserialize fields as well as properties. `System.Text.Json` only works with properties. @@ -283,7 +288,7 @@ The `Newtonsoft.Json` `JsonConvert.PopulateObject` method deserializes a JSON do ### Reuse rather than replace properties -The `Newtonsoft.Json` `ObjetCreationHandling` setting lets you specify that objects in properties should be reused rather than replaced during deserialization. `System.Text.Json` always replaces objects in properties. +The `Newtonsoft.Json` `ObjectCreationHandling` setting lets you specify that objects in properties should be reused rather than replaced during deserialization. `System.Text.Json` always replaces objects in properties. ### Add to collections without setters @@ -325,17 +330,19 @@ Searches that use `Newtonsoft.Json` `JObject` or `JArray` tend to be relatively For a code example, see [Use JsonDocument for access to data](system-text-json-how-to.md#use-jsondocument-for-access-to-data). -## Utf8JsonReader and Utf8JsonWriter +## Utf8JsonReader 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. - 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 `Utf8JsonReader`. -The following sections explain recommended programming patterns for using `Utf8JsonReader` and `Utf8JsonWriter`. +### Ref struct -### Ref structs +The `Utf8JsonReader` type is a *ref struct*, which means it has certain limitations. 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 `Span`, which itself is a ref struct. In addition, this type is mutable since it holds state. Therefore, you should **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 and write with UTF-8 text -The `Utf8JsonReader` and `Utf8JsonWriter` types are *ref structs*, which means they have certain limitations. For example, they can't be stored as a field on a class or struct other than a ref struct. To achieve high performance, these types must be `ref structs` since they need to cache the input or output `Span`, which itself is a ref struct. In addition, these types are mutable since they hold state. Therefore, you should **pass them by ref** rather than by value. Passing them 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` and `JsonTextWriter` are classes. For more information about how to use ref structs, see [Write safe and efficient C# code](../../csharp/write-safe-efficient-code.md). +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 @@ -359,20 +366,7 @@ while (reader.Read()) } ``` -### WRiteRawValue - -The `Newtonsoft.Json` `WriteRawValue` method writes raw JSON where a value is expected. `System.Text.Json` has no direct equivalent, but here's a workaround: - -```csharp -using JsonDocument doc = JsonDocument.Parse(string); -doc.WriteTo(writer); -``` - -### Read and write with UTF-8 text - -To achieve the best possible performance while using the `Utf8JsonReader` and `Utf8JsonWriter`, read and write JSON payloads already encoded as UTF-8 text rather than as UTF-16 strings. For example, if you're writing string literals, consider caching them as static byte arrays, and write those instead. For a code example, see [Filter data using Utf8JsonReader](system-text-json-how-to.md#filter-data-using-utf8jsonreader). - -### Read and write null values +### Read null values Code that uses the `Newtonsoft.Json` reader can compare a value token type of String to null, as in the following example: @@ -411,6 +405,34 @@ public static string ReadAsString(this ref Utf8JsonReader reader) } ``` +### 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 [.NET Core installer](https://github.com/dotnet/runtime/tree/master/src/installer) follows: + +* [UnifiedJsonReader.JsonTextReader.cs](https://github.com/dotnet/runtime/blob/35fe82c2e90fa345d0b6ad243c14da193fb123fd/src/installer/managed/Microsoft.Extensions.DependencyModel/UnifiedJsonReader.JsonTextReader.cs) +* [UnifiedJsonReader.Utf8JsonReader.cs](https://github.com/dotnet/runtime/blob/35fe82c2e90fa345d0b6ad243c14da193fb123fd/src/installer/managed/Microsoft.Extensions.DependencyModel/UnifiedJsonReader.Utf8JsonReader.cs) + +## Utf8JsonWriter + + 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. For example, if you're writing string literals, consider caching them as static byte arrays, and write those instead. + +### WriteRawValue + +The `Newtonsoft.Json` `WriteRawValue` method writes raw JSON where a value is expected. `System.Text.Json` has no direct equivalent, but here's a workaround: + +```csharp +using JsonDocument doc = JsonDocument.Parse(string); +doc.WriteTo(writer); +``` + +### Write null values + To write null values by using `Utf8JsonWriter`, call: * to write a key-value pair with null as the value. @@ -420,14 +442,12 @@ For a string property, if the string is null, * [System.Text.Json overview](system-text-json-overview.md) From 0f9a494dfedf66479be4e366154cd754efa19e65 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Fri, 27 Dec 2019 11:16:14 -0800 Subject: [PATCH 34/74] reapply change lost earlier --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index fecbf78bdd9a5..b7d81fc981346 100644 --- 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 @@ -14,7 +14,7 @@ helpviewer_keywords: This article shows how to migrate from [Newtonsoft.Json](https://www.newtonsoft.com/json) to [System.Text.Json](system-text-json-overview.md). -`System.Text.Json` focuses primarily on performance, security, and standards compliance. It lacks built-in features to handle some common scenarios, and some default behaviors differ from `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 that has no workaround, consider delaying your migration to `System.Text.Json`. + `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. From 16b73b317c0c118dc0e64d7cbfe9461145cf6576 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Sat, 28 Dec 2019 13:13:14 -0800 Subject: [PATCH 35/74] remove dbnull comments --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 4 ---- 1 file changed, 4 deletions(-) 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 index b7d81fc981346..76f6ae454f825 100644 --- 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 @@ -245,10 +245,6 @@ Workarounds may be possible for some of the following scenarios, but they would * * -Custom converters for some of these types would not necessarily be complex. Here's an example of a `DBNull` converter that just converts `DBNull` to `null`: - -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/DBNullConverter.cs)] - ### Fields `Newtonsoft.Json` can serialize and deserialize fields as well as properties. `System.Text.Json` only works with properties. From 4618b0cd2dc8d5eaa6ff7a0d9ca250a787d5e8f5 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 31 Dec 2019 09:27:23 -0800 Subject: [PATCH 36/74] Apply suggestions from code review Co-Authored-By: Ahson Khan --- ...ext-json-migrate-from-newtonsoft-how-to.md | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) 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 index 76f6ae454f825..0c8101868b82d 100644 --- 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 @@ -18,7 +18,7 @@ This article shows how to migrate from [Newtonsoft.Json](https://www.newtonsoft. -Most of this article is about how to use the API, but it also includes guidance on how to use the Document Object Model (DOM) and the and API. The article is organized into sections in the following order: +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), the and the types. The article is organized into sections in the following order: * [Differences in **default** JsonSerializer behavior compared to Newtonsoft.Json](#differences-in-default-behavior). * [Scenarios using JsonSerializer that require workarounds](#scenarios-using-jsonserializer-that-require-workarounds). @@ -27,13 +27,13 @@ Most of this article is about how to use the `, it: * "Guesses" the type of "primitive" values in the JSON and stores `string`/`long`/`double`/`boolean`/`DateTime` as a boxed object. -* Stores "complex" values as `JObject`. -* Stores `null` when the payload has "null". +* Returns the stored complex values as a `JObject` or `JArray`. *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. -`System.Text.Json` stores a boxed `JsonElement` for "primitive" and "complex" values within the System.Object property or dictionary value. It stores `null` when the payload has "null" in it. +`System.Text.Json` 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). @@ -89,11 +89,14 @@ The following scenarios aren't supported by built-in functionality, but sample c ### Specify date format -`Newtonsoft.Json` provides a `DateTimeZoneHandling` option that lets you specify the serialization format used for `DateTime` and `DateTimeOffset` properties. In `System.Text.Json`, the only format that has built-in support is ISO 8601-1:2019. 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). +`Newtonsoft.Json` provides a `DateTimeZoneHandling` option that lets you specify the serialization format used for `DateTime` and `DateTimeOffset` properties. In `System.Text.Json`, the only format that has built-in support is ISO 8601-1:2019 since it is 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 in quotes. For example, it can accept: `{ "DegreesCelsius":"23" }` instead of `{ "DegreesCelsius":23 }`. To enable that behavior in `System.Text.Json`, implement a custom converter like the following example, which uses quotes for properties defined as `long`. +`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 `System.Text.Json`, 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)] @@ -134,7 +137,7 @@ To make deserialization fail if no `Date` property is in the JSON, implement a c If you follow this pattern, 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 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. -This is a simplified example. More complex code would be required if you need to handle attributes (such as `[JsonIgnore]`) or options (such as custom encoders). +This is a simplified example. Additional logic would be required if you need to handle attributes (such as `[JsonIgnore]`) or different options (such as custom encoders). ### Deserialize null to non-nullable type From 1bcb4f3f2c4cf37221a214510acbd3111a3a6bac Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 31 Dec 2019 09:35:41 -0800 Subject: [PATCH 37/74] Apply suggestion from code review Co-Authored-By: Ahson Khan --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 0c8101868b82d..bf2b4b1c41f9d 100644 --- 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 @@ -71,7 +71,7 @@ During serialization, `Newtonsoft.Json` is relatively permissive about letting c When `Newtonsoft.Json` deserializes to `Object` properties in POCOs or in dictionaries of type `Dictionary`, it: -* "Guesses" the type of "primitive" values in the JSON and stores `string`/`long`/`double`/`boolean`/`DateTime` as a boxed object. +* 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 the stored complex values as a `JObject` or `JArray`. *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. From 66dbd62f146323e0890b4d5d69e7cebe2184a045 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 31 Dec 2019 10:02:26 -0800 Subject: [PATCH 38/74] ahson feedback --- .../system-text-json-converters-how-to.md | 10 ++++----- ...ext-json-migrate-from-newtonsoft-how-to.md | 22 ++++++++----------- 2 files changed, 14 insertions(+), 18 deletions(-) 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 6f42d7048b9d4..732b0f89ac4ce 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -284,11 +284,11 @@ The [Migrate from Newtonsoft.Json to System.Text.Json](system-text-json-migrate- The [unit tests folder](https://github.com/dotnet/runtime/blob/f77914d4c9045a01b3a91b63c28805f24850c274/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 -* `Int32` converter that allows both string and number values on deserialize -* `Enum` converter -* `List` converter that accepts external data -* `Long[]` converter that works with a comma-delimited list of numbers +* [Int32 converter that converts null to 0 on deserialize](https://github.com/dotnet/runtime/blob/f77914d4c9045a01b3a91b63c28805f24850c274/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/f77914d4c9045a01b3a91b63c28805f24850c274/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Int32.cs) +* [Enum converter](https://github.com/dotnet/runtime/blob/f77914d4c9045a01b3a91b63c28805f24850c274/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Enum.cs) +* [List\ converter that accepts external data](https://github.com/dotnet/runtime/blob/f77914d4c9045a01b3a91b63c28805f24850c274/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/f77914d4c9045a01b3a91b63c28805f24850c274/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/f77914d4c9045a01b3a91b63c28805f24850c274/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters) to serve as a starting point for customization. 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 index 0c8101868b82d..8a12e0bde84c5 100644 --- 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 @@ -20,12 +20,12 @@ This article shows how to migrate from [Newtonsoft.Json](https://www.newtonsoft. 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), the and the types. The article is organized into sections in the following order: -* [Differences in **default** JsonSerializer behavior compared to Newtonsoft.Json](#differences-in-default-behavior). -* [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](#jsondocument). -* [Utf8JsonReader](#utf8jsonreader). -* [Utf8JsonWriter](#utf8jsonwriter). +* [Differences in **default** JsonSerializer behavior compared to Newtonsoft.Json](#differences-in-default-behavior) +* [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](#jsondocument) +* [Utf8JsonReader](#utf8jsonreader) +* [Utf8JsonWriter](#utf8jsonwriter) ## Differences in default JsonSerializer behavior compared to Newtonsoft.Json @@ -85,7 +85,7 @@ To implement type inference for `Object` properties, create a converter like the ## Scenarios using JsonSerializer that require workarounds -The following scenarios aren't supported by built-in functionality, but sample code is provided for 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 @@ -100,7 +100,7 @@ The following scenarios aren't supported by built-in functionality, but sample c [!code-csharp[](~/samples/snippets/core/system-text-json/csharp/LongToStringConverter.cs)] -[Register this custom converter](system-text-json-converters-how-to.md#register-a-custom-converter) by using an attribute on individual `long` properties or by adding the converter to the `Converters` collection. +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 to the `Converters` collection](system-text-json-converters-how-to.md#registration-sample---converters-collection). ### Dictionary with non-string key @@ -110,7 +110,7 @@ To support a dictionary with an integer or some other type as the key, create a ### Polymorphic deserialization -`Newtonsoft.Json` provides attributes that specify how to handle polymorphic deserialization scenarios. `System.Text.Json` doesn't provide such attributes. `System.Text.Json` can do [polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes) but not polymorphic deserialization or conversion of the same data in both directions. +`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. `System.Text.Json` can do [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). @@ -277,10 +277,6 @@ By default, `Newtonsoft.Json` serializes by value. For example, if an object con `Newtonsoft.Json` treats numbers with a leading zero as octal numbers. `System.Text.Json` doesn't allow leading zeroes because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't allow them. -### Type name handling - -`Newtonsoft.Json` has a `TypeNameHandling` setting that adds type name metadata to the JSON while serializing, and it uses the metadata while deserializing. `System.Text.Json` lacks this feature. - ### Populate existing objects The `Newtonsoft.Json` `JsonConvert.PopulateObject` method deserializes a JSON document to an existing instance of a class, instead of creating a new instance. `System.Text.Json` always creates a new instance of the target type by using the default parameterless constructor. From 6fc63771364cf8d084294f7a7edcba94add87c1f Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 31 Dec 2019 10:17:42 -0800 Subject: [PATCH 39/74] make registration links more specific --- ...tem-text-json-migrate-from-newtonsoft-how-to.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) 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 index 7033457fc0bce..b1f839aa8f9fa 100644 --- 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 @@ -20,7 +20,7 @@ This article shows how to migrate from [Newtonsoft.Json](https://www.newtonsoft. 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), the and the types. The article is organized into sections in the following order: -* [Differences in **default** JsonSerializer behavior compared to Newtonsoft.Json](#differences-in-default-behavior) +* [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](#jsondocument) @@ -133,7 +133,7 @@ To make deserialization fail if no `Date` property is in the JSON, implement a c [!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecastRequiredPropertyConverter.cs)] -[Register this custom converter](system-text-json-converters-how-to.md#register-a-custom-converter) by using an attribute on the POCO class or by adding the converter to the `Converters` collection. +Register this custom converter by [using an attribute](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-type) on the POCO class or by [adding the converter to the `Converters` collection](system-text-json-converters-how-to.md#registration-sample---converters-collection). If you follow this pattern, 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 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. @@ -154,7 +154,7 @@ Another workaround is to make a converter for the type, such as the following ex [!code-csharp[](~/samples/snippets/core/system-text-json/csharp/DateTimeOffsetNullHandlingConverter.cs)] -[Register this custom converter](system-text-json-converters-how-to.md#register-a-custom-converter) by using an attribute on the property or by adding the converter to the `Converters` collection. +Register this custom converter by [using an attribute](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-property) on the property or by [adding the converter to the `Converters` collection](system-text-json-converters-how-to.md#registration-sample---converters-collection). ### Deserialize to immutable classes and structs @@ -168,7 +168,7 @@ 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](system-text-json-converters-how-to.md#register-a-custom-converter) by adding the converter to the `Converters` collection. +Register this custom converter by [adding the converter to the `Converters` collection](system-text-json-converters-how-to.md#registration-sample---converters-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/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterKeyValuePair.cs). @@ -204,9 +204,9 @@ For that functionality, you can write a custom converter. Here's a sample POCO a 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](system-text-json-converters-how-to.md#register-a-custom-converter) by adding the converter to the `Converters` collection or by applying the `[JsonConvert]` attribute to the class. +Register this custom converter by [using an attribute](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-type) on the class or by [adding the converter to the `Converters` collection](system-text-json-converters-how-to.md#registration-sample---converters-collection). -This approach requires complex code if: +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. @@ -224,7 +224,7 @@ In `System.Text.Json`, you can simulate callbacks by writing a custom converter. [!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecastCallbacksConverter.cs)] -[Register the converter](system-text-json-converters-how-to.md#register-a-custom-converter) by adding the converter to the `Converters` collection or by applying the `[JsonConvert]` attribute to the class. +Register this custom converter by [using an attribute](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-type) on the class or by [adding the converter to the `Converters` collection](system-text-json-converters-how-to.md#registration-sample---converters-collection). If you use a custom converter that follows this example: From 57fb760362abdcdf9b93a6f3ac4407112e9fb683 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 31 Dec 2019 16:06:38 -0800 Subject: [PATCH 40/74] add converters api link --- ...ystem-text-json-migrate-from-newtonsoft-how-to.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 index b1f839aa8f9fa..669c3b6d019b1 100644 --- 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 @@ -100,7 +100,7 @@ The following scenarios aren't supported by built-in functionality, but sample c [!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 to the `Converters` collection](system-text-json-converters-how-to.md#registration-sample---converters-collection). +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 @@ -133,7 +133,7 @@ To make deserialization fail if no `Date` property is in the JSON, implement a c [!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecastRequiredPropertyConverter.cs)] -Register this custom converter by [using an attribute](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-type) on the POCO class or by [adding the converter to the `Converters` collection](system-text-json-converters-how-to.md#registration-sample---converters-collection). +Register this custom converter by [using an attribute](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-type) on the POCO class 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 `Serialize` or `Deserialize`. The options object contains the `Converters` 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. @@ -154,7 +154,7 @@ Another workaround is to make a converter for the type, such as the following ex [!code-csharp[](~/samples/snippets/core/system-text-json/csharp/DateTimeOffsetNullHandlingConverter.cs)] -Register this custom converter by [using an attribute](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-property) on the property or by [adding the converter to the `Converters` collection](system-text-json-converters-how-to.md#registration-sample---converters-collection). +Register this custom converter by [using an attribute](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-property) on the property or by [adding the converter](system-text-json-converters-how-to.md#registration-sample---converters-collection) to the collection. ### Deserialize to immutable classes and structs @@ -168,7 +168,7 @@ 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 to the `Converters` collection](system-text-json-converters-how-to.md#registration-sample---converters-collection). +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/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterKeyValuePair.cs). @@ -204,7 +204,7 @@ For that functionality, you can write a custom converter. Here's a sample POCO a 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](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-type) on the class or by [adding the converter to the `Converters` collection](system-text-json-converters-how-to.md#registration-sample---converters-collection). +Register this custom converter by [using an attribute](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-type) on the class 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: @@ -224,7 +224,7 @@ In `System.Text.Json`, you can simulate callbacks by writing a custom converter. [!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecastCallbacksConverter.cs)] -Register this custom converter by [using an attribute](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-type) on the class or by [adding the converter to the `Converters` collection](system-text-json-converters-how-to.md#registration-sample---converters-collection). +Register this custom converter by [using an attribute](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-type) on the class 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 this example: From 35434dd02dab071f31f43cba55ef4373739a18aa Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 31 Dec 2019 16:15:18 -0800 Subject: [PATCH 41/74] Apply suggestions from code review Co-Authored-By: Ahson Khan --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 index 669c3b6d019b1..7ad60e6ba9b95 100644 --- 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 @@ -158,7 +158,7 @@ Register this custom converter by [using an attribute](system-text-json-converte ### Deserialize to immutable classes and structs -`Newtonsoft.Json` can deserialize to immutable classes and structs because it can use constructors that have parameters. `System.Text.Json` supports only parameterless constructors. As a workaround, you can call a constructor with parameters in a custom converter. +`Newtonsoft.Json` can deserialize to immutable classes and structs because it can use constructors that have parameters. `System.Text.Json` 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: @@ -181,7 +181,7 @@ The `Newtonsoft.Json` `[JsonConstructor]` attribute lets you specify which const `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` setting on `JsonSerializerOptions` lets you specify that all null-value or default-value properties should be ignored. +* The `NullValueHandling` and `DefaultValueHandling` setting on `JsonSerializerSettings` lets you specify that all null-value or default-value properties should be ignored. * The `NullValueHandling` and `DefaultValueHandling` setting on `[JsonProperty]` attribute lets you specify individual properties that should be ignored when set to null or default value. `System.Text.Json` provides the following ways to omit properties while serializing: @@ -189,7 +189,7 @@ The `Newtonsoft.Json` `[JsonConstructor]` attribute lets you specify which const * 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. -These options don't let you: +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. @@ -226,7 +226,7 @@ In `System.Text.Json`, you can simulate callbacks by writing a custom converter. Register this custom converter by [using an attribute](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-type) on the class 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 this example: +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. From 93d7564a35ec37f7c8a5e0365b60b26497e860b8 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 31 Dec 2019 17:24:49 -0800 Subject: [PATCH 42/74] add note to null-to-nonnullable section --- ...-text-json-migrate-from-newtonsoft-how-to.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) 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 index 7ad60e6ba9b95..c41186b5fc911 100644 --- 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 @@ -156,6 +156,22 @@ Another workaround is to make a converter for the type, such as the following ex Register this custom converter by [using an attribute](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-property) on the property or by [adding the converter](system-text-json-converters-how-to.md#registration-sample---converters-collection) to the collection. +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. `System.Text.Json` supports only public parameterless constructors. As a workaround, you can call a constructor with parameters in a custom converter. @@ -188,6 +204,7 @@ The `Newtonsoft.Json` `[JsonConstructor]` attribute lets you specify which const * 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: From 2610c4acbd605c014157cbf3ee86ec65c9d67dcf Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 31 Dec 2019 18:54:09 -0800 Subject: [PATCH 43/74] Update docs/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to.md Co-Authored-By: Ahson Khan --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index c41186b5fc911..a97f0343e4160 100644 --- 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 @@ -143,7 +143,7 @@ This is a simplified example. Additional logic would be required if you need to `Newtonsoft.Json` doesn't throw an exception in the following scenario: -* `NullValueHandling` is set to `Ignore` +* `NullValueHandling` is set to `Ignore`, and * During deserialization, the JSON contains a null value for a non-nullable type. In the same scenario, `System.Text.Json` does throw an exception. (The corresponding null handling setting is .) From 957f97624d4503ce35ef93701d5c21ee04689045 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 31 Dec 2019 19:21:25 -0800 Subject: [PATCH 44/74] Apply suggestions from code review Co-Authored-By: Ahson Khan --- ...ext-json-migrate-from-newtonsoft-how-to.md | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) 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 index a97f0343e4160..351c6b227d08c 100644 --- 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 @@ -265,13 +265,13 @@ Workarounds may be possible for some of the following scenarios, but they would * * -### Fields +### Public and non-public fields -`Newtonsoft.Json` can serialize and deserialize fields as well as properties. `System.Text.Json` only works with properties. +`Newtonsoft.Json` can serialize and deserialize fields as well as properties. `System.Text.Json` only works with public properties. -### Private setters +### Internal and private property setters and getters -`Newtonsoft.Json` can use private property setters. `System.Text.Json` supports only public setters. +`Newtonsoft.Json` can use private and internal property setters and getters via the `JsonProperty` attribute. `System.Text.Json` supports only public setters. ### Preserve object references and handle loops @@ -279,12 +279,12 @@ By default, `Newtonsoft.Json` serializes by value. For example, if an object con `Newtonsoft.Json` has a `PreserveReferencesHandling` setting on `JsonSerializerSettings` that lets you serialize by reference: -* A token is added to the JSON created for the first `Person` object. -* The JSON that is created for the second `Person` object contains that token instead of property values. +* An id 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 id instead of property values. `Newtonsoft.Json` also has a `ReferenceLoopHandling` setting that lets you ignore circular references rather than throw an exception. -`System.Text.Json` supports only serialization by value. +`System.Text.Json` only supports serialization by value and throws an exception for circular references. ### System.Runtime.Serialization attributes @@ -296,7 +296,7 @@ By default, `Newtonsoft.Json` serializes by value. For example, if an object con ### Populate existing objects -The `Newtonsoft.Json` `JsonConvert.PopulateObject` method deserializes a JSON document to an existing instance of a class, instead of creating a new instance. `System.Text.Json` always creates a new instance of the target type by using the default parameterless constructor. +The `JsonConvert.PopulateObject` method in `Newtonsoft.Json` deserializes a JSON document to an existing instance of a class, instead of creating a new instance. `System.Text.Json` always creates a new instance of the target type by using the default public parameterless constructor. ### Reuse rather than replace properties @@ -308,37 +308,37 @@ During deserialization, `Newtonsoft.Json` adds objects to a collection even if t ### MissingMemberHandling -`Newtonsoft.Json` can be configured to throw exceptions during deserialization if the JSON includes properties that are missing in the target type. `System.Text.Json` 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. +`Newtonsoft.Json` can be configured to throw exceptions during deserialization if the JSON includes properties that are missing in the target type. `System.Text.Json` 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. `System.Text.Json` doesn't do logging. -## JsonDocument +## JsonDocument and JsonElement compared to Newtonsoft.Json's JToken (like JObject, JArray) - provides the ability to build a read-only Document Object Model (DOM). 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. + 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. ### IDisposable -`JsonDocument` builds an in-memory view of the data into a pooled buffer. Therefore, unlike `Newtonsoft.Json` `JObject` or `JArray`, the `JsonDocument` type implements `IDisposable` and needs to be used inside a using block. +`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. ### Read-only -Since the `System.Text.Json` DOM can't add, remove, or modify JSON elements. If your scenario currently uses a writable DOM, one of the following workarounds might be feasible: +The `System.Text.Json` 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 writable/modifiable DOM, one of the following workarounds might be feasible: -* To build a `JsonDocument` from scratch, write JSON text by using the `Utf8JsonWriter` and parse the output from that to make a new `JsonDocument`. +* 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`. ### JsonElement -`JsonDocument` exposes the `RootElement` as a property of type , which is the type that encompasses any JSON element. `Newtonsoft.Json` uses dedicated 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. +`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. ### Search a JsonDocument -Searches that use `Newtonsoft.Json` `JObject` or `JArray` tend to be relatively fast because they're lookups in some dictionary. By comparison, a sequential search through JSON elements stored as `JsonElement` is relatively slow. `System.Text.Json` is designed to minimize initial parse time rather than look-up time. Therefore, use the following approaches to optimize performance when searching through a `JsonDocument` object: +Searches for JSON tokens using `JObject` or `JArray` from `Newtonsoft.Json` tend to be relatively fast because they're look-ups 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`). `System.Text.Json` is designed to minimize initial parse time rather than look-up 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 of every `JsonElement`. 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. +* 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 do 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). From 9fc486a2e2674731b5a8a187a84800cdf7c492e5 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 31 Dec 2019 19:28:21 -0800 Subject: [PATCH 45/74] fix link --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index 351c6b227d08c..60827a7fa2771 100644 --- 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 @@ -23,7 +23,7 @@ Most of this article is about how to use the 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. From bc30ca21067e0993b2fc77b3f4983ed7befa7ad8 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Wed, 1 Jan 2020 11:19:47 -0800 Subject: [PATCH 46/74] acrolinx and feedback --- ...ext-json-migrate-from-newtonsoft-how-to.md | 46 +++++++++++++++---- 1 file changed, 38 insertions(+), 8 deletions(-) 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 index 60827a7fa2771..b60ee4961b37a 100644 --- 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 @@ -18,7 +18,7 @@ This article shows how to migrate from [Newtonsoft.Json](https://www.newtonsoft. -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), the and the types. The article is organized into sections in the following order: +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) @@ -45,6 +45,20 @@ During deserialization, `Newtonsoft.Json` ignores comments in the JSON by defaul During deserialization, `Newtonsoft.Json` ignores trailing commas by default. It also ignores multiple trailing commas (for example, `[{"Color":"Red"},{"Color":"Green"},,]`). The `System.Text.Json` default is to throw exceptions for trailing commas because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't include them. For information about how to allow trailing commas, 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. +### Property names + +During deserialization, `Newtonsoft.Json` accepts property names surrounded by double quotes, single quotes, or without quotes. For example: + +```json +{ + "name1": "value", + 'name2': "value", + name3: "value" +} +``` + +`System.Text.Json` only accepts names in double quotes because that format is required by the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification. + ### Converter registration precedence The `Newtonsoft.Json` registration precedence for custom converters is as follows: @@ -72,8 +86,8 @@ During serialization, `Newtonsoft.Json` is relatively permissive about letting c 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 the stored complex values as a `JObject` or `JArray`. *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. +* Returns the stored complex values as a `JObject` or `JArray`. *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. `System.Text.Json` 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. @@ -83,17 +97,26 @@ To implement type inference for `Object` properties, create a converter like the `Newtonsoft.Json` doesn't have a maximum depth limit. For `System.Text.Json` there's a default limit of 64, and it's configurable by setting (xref:System.Text.Json.JsonSerializerOptions.MaxDepth?displayProperty=nameWithType). +### Stack type handling + +Properties of type and don't have the same value after making a round trip to and from JSON. The order of a stack's contents is reversed when it's serialized. A custom converter could be implemented to keep stack contents in the same order. + ## 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 a `DateTimeZoneHandling` option that lets you specify the serialization format used for `DateTime` and `DateTimeOffset` properties. In `System.Text.Json`, the only format that has built-in support is ISO 8601-1:2019 since it is 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). +`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 `System.Text.Json`, 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 `System.Text.Json`, implement a custom converter like the following example. The converter handles properties defined as `long`: +`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 `System.Text.Json`, 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. @@ -137,7 +160,11 @@ Register this custom converter by [using an attribute](system-text-json-converte If you follow this pattern, 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 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. -This is a simplified example. Additional logic would be required if you need to handle attributes (such as `[JsonIgnore]`) or different options (such as custom encoders). +The preceding converter code is a simplified example. Additional logic would be required if you need to handle attributes (such as `[JsonIgnore]`) 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 @@ -250,7 +277,7 @@ If you use a custom converter that follows the preceding sample: ## Scenarios that JsonSerializer currently doesn't support -Workarounds may be possible for some of the following scenarios, but they would be relatively difficult or impractical to implement. +Workarounds are possible for the following scenarios, but some of them would be relatively difficult to implement. Code samples for workarounds are not available for these scenarios. ### Types without built-in support @@ -264,10 +291,13 @@ Workarounds may be possible for some of the following scenarios, but they would * * * +* + +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. `System.Text.Json` only works with public properties. +`Newtonsoft.Json` can serialize and deserialize fields as well as properties. `System.Text.Json` only works with public properties. ### Internal and private property setters and getters From 9a057bbe1c3459b522dca7ab43030a3264eeee8a Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Wed, 1 Jan 2020 12:09:42 -0800 Subject: [PATCH 47/74] add workaround notes --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 index b60ee4961b37a..f7b41fa48d335 100644 --- 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 @@ -297,11 +297,11 @@ 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. `System.Text.Json` only works with public properties. +`Newtonsoft.Json` can serialize and deserialize fields as well as properties. `System.Text.Json` 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. `System.Text.Json` supports only public setters. +`Newtonsoft.Json` can use private and internal property setters and getters via the `JsonProperty` attribute. `System.Text.Json` supports only public setters. Custom converters can provide this functionality. ### Preserve object references and handle loops @@ -326,15 +326,15 @@ By default, `Newtonsoft.Json` serializes by value. For example, if an object con ### 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. `System.Text.Json` always creates a new instance of the target type by using the default public parameterless constructor. +The `JsonConvert.PopulateObject` method in `Newtonsoft.Json` deserializes a JSON document to an existing instance of a class, instead of creating a new instance. `System.Text.Json` always creates a new instance of the target type by using the default public parameterless constructor. Custom converters can provide this functionality. ### 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. `System.Text.Json` always replaces objects in properties. +The `Newtonsoft.Json` `ObjectCreationHandling` setting lets you specify that objects in properties should be reused rather than replaced during deserialization. `System.Text.Json` 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. `System.Text.Json` ignores properties that don't have setters. +During deserialization, `Newtonsoft.Json` adds objects to a collection even if the property has no setter. `System.Text.Json` ignores properties that don't have setters. Custom converters can provide this functionality. ### MissingMemberHandling From 93194b2f7af120da4b2b4086beb879ba745d7569 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Mon, 6 Jan 2020 11:18:47 -0800 Subject: [PATCH 48/74] first occurrrences of STJ --> xref link --- ...ext-json-migrate-from-newtonsoft-how-to.md | 70 +++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) 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 index f7b41fa48d335..1983e7c2be7ed 100644 --- 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 @@ -12,7 +12,7 @@ helpviewer_keywords: # 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](system-text-json-overview.md). +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. @@ -29,21 +29,21 @@ Most of this article is about how to use the 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. ### Case-insensitive deserialization -During deserialization, `Newtonsoft.Json` does case-insensitive property name matching by default. The `System.Text.Json` 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). +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 case-insensitive setting when it uses `System.Text.Json`. ### Comments -During deserialization, `Newtonsoft.Json` ignores comments in the JSON by default. The `System.Text.Json` 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). +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 `System.Text.Json` default is to throw exceptions for trailing commas because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't include them. For information about how to allow trailing commas, 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. +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 include them. For information about how to allow trailing commas, 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. ### Property names @@ -69,7 +69,7 @@ The `Newtonsoft.Json` registration precedence for custom converters is as follow 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 `System.Text.Json` registration precedence for custom converters is different: +The registration precedence for custom converters is different: * Attribute on property * collection @@ -79,7 +79,7 @@ The difference here is that a custom converter in the `Converters` collection ov ### 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 `\"`). `System.Text.Json` 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). +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 @@ -89,17 +89,17 @@ When `Newtonsoft.Json` deserializes to `Object` properties in POCOs or in dictio * Returns the stored complex values as a `JObject` or `JArray`. *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. -`System.Text.Json` 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. + 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. For `System.Text.Json` there's a default limit of 64, and it's configurable by setting (xref:System.Text.Json.JsonSerializerOptions.MaxDepth?displayProperty=nameWithType). +`Newtonsoft.Json` doesn't have a maximum depth limit. For there's a default limit of 64, and it's configurable by setting (xref:System.Text.Json.JsonSerializerOptions.MaxDepth?displayProperty=nameWithType). ### Stack type handling -Properties of type and don't have the same value after making a round trip to and from JSON. The order of a stack's contents is reversed when it's serialized. A custom converter could be implemented to keep stack contents in the same order. +In , properties of type and don't have the same value after making a round trip to and from JSON. The order of a stack's contents is reversed when it's serialized. A custom converter could be implemented to keep stack contents in the same order. ## Scenarios using JsonSerializer that require workarounds @@ -112,11 +112,11 @@ The following scenarios aren't supported by built-in functionality, but sample c * 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 `System.Text.Json`, 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). +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 `System.Text.Json`, implement a custom converter like the following example. The converter handles properties defined as `long`: +`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. @@ -127,19 +127,19 @@ Register this custom converter by [using an attribute](system-text-json-converte ### Dictionary with non-string key -`Newtonsoft.Json` supports collections of type `Dictionary`. The built-in support for dictionary collections in `System.Text.Json` is limited to `Dictionary`. That is, the key must be a string. +`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 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. `System.Text.Json` can do [polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes) but not 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 [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, `System.Text.Json` 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: +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)] @@ -173,7 +173,7 @@ The preceding converter code is a simplified example. Additional logic would be * `NullValueHandling` is set to `Ignore`, and * During deserialization, the JSON contains a null value for a non-nullable type. -In the same scenario, `System.Text.Json` does throw an exception. (The corresponding null handling setting is .) +In the same scenario, does throw an exception. (The corresponding null handling setting is .) If you own the target type, the easiest workaround is to make the property in question nullable (for example, change `int` to `int?`). @@ -201,7 +201,7 @@ After deserialization, the `Date` property has 1/1/0001 (`default(DateTimeOffset ### Deserialize to immutable classes and structs -`Newtonsoft.Json` can deserialize to immutable classes and structs because it can use constructors that have parameters. `System.Text.Json` supports only public parameterless constructors. As a workaround, you can call a constructor with parameters in a custom converter. +`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: @@ -217,7 +217,7 @@ For an example of a similar converter that handles open generic properties, see ### Specify constructor to use -The `Newtonsoft.Json` `[JsonConstructor]` attribute lets you specify which constructor to call when deserializing to a POCO. `System.Text.Json` 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). +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 @@ -227,7 +227,7 @@ The `Newtonsoft.Json` `[JsonConstructor]` attribute lets you specify which const * The `NullValueHandling` and `DefaultValueHandling` setting on `JsonSerializerSettings` lets you specify that all null-value or default-value properties should be ignored. * The `NullValueHandling` and `DefaultValueHandling` setting on `[JsonProperty]` attribute lets you specify individual properties that should be ignored when set to null or default value. -`System.Text.Json` provides the following ways to omit properties while serializing: + 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. @@ -264,7 +264,7 @@ This approach requires additional logic if: * OnSerializing (when beginning to serialize an object) * OnSerialized (when finished serializing an object) -In `System.Text.Json`, 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. +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)] @@ -281,7 +281,7 @@ Workarounds are possible for the following scenarios, but some of them would be ### Types without built-in support -`System.Text.Json` doesn't provide built-in support for the following types: + 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). @@ -297,11 +297,11 @@ 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. `System.Text.Json` only works with public properties. Custom converters can provide this functionality. +`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. `System.Text.Json` supports only public setters. Custom converters can provide this functionality. +`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 @@ -314,35 +314,35 @@ By default, `Newtonsoft.Json` serializes by value. For example, if an object con `Newtonsoft.Json` also has a `ReferenceLoopHandling` setting that lets you ignore circular references rather than throw an exception. -`System.Text.Json` only supports serialization by value and throws an exception for circular references. + only supports serialization by value and throws an exception for circular references. ### System.Runtime.Serialization attributes -`System.Text.Json` doesn't support attributes from the `System.Runtime.Serialization` namespace, such as `DataMemberAttribute` and `IgnoreDataMemberAttribute`. + 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. `System.Text.Json` doesn't allow leading zeroes because the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification doesn't allow them. +`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. `System.Text.Json` always creates a new instance of the target type by using the default public parameterless constructor. Custom converters can provide this functionality. +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 provide this functionality. ### 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. `System.Text.Json` always replaces objects in properties. Custom converters can provide this functionality. +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. `System.Text.Json` ignores properties that don't have setters. Custom converters can provide this functionality. +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. `System.Text.Json` 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. +`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. `System.Text.Json` doesn't do logging. +`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) @@ -354,7 +354,7 @@ During deserialization, `Newtonsoft.Json` adds objects to a collection even if t ### Read-only -The `System.Text.Json` 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 writable/modifiable DOM, one of the following workarounds might be feasible: +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 writable/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`. @@ -365,7 +365,7 @@ The `System.Text.Json` DOM can't add, remove, or modify JSON elements. It's desi ### Search a JsonDocument -Searches for JSON tokens using `JObject` or `JArray` from `Newtonsoft.Json` tend to be relatively fast because they're look-ups 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`). `System.Text.Json` is designed to minimize initial parse time rather than look-up time. Therefore, use the following approaches to optimize performance when searching through a `JsonDocument` object: +Searches for JSON tokens using `JObject` or `JArray` from `Newtonsoft.Json` tend to be relatively fast because they're look-ups 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 look-up 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 do unnecessary passes over the same data. @@ -426,7 +426,7 @@ public static string ReadAsString(this JsonTextReader reader) } ``` -This code doesn't work correctly in `System.Text.Json`, which considers the `null` literal to be its own token type. When using `Utf8JsonReader`, check for the `JsonTokenType.Null` token type, as shown in the following example: +This code doesn't work correctly in , which considers the `null` literal to be its own token type. When using `Utf8JsonReader`, check for the `JsonTokenType.Null` token type, as shown in the following example: ```csharp public static string ReadAsString(this ref Utf8JsonReader reader) @@ -466,7 +466,7 @@ To achieve the best possible performance while using the `Utf8JsonWriter`, write ### WriteRawValue -The `Newtonsoft.Json` `WriteRawValue` method writes raw JSON where a value is expected. `System.Text.Json` has no direct equivalent, but here's a workaround: +The `Newtonsoft.Json` `WriteRawValue` method writes raw JSON where a value is expected. has no direct equivalent, but here's a workaround: ```csharp using JsonDocument doc = JsonDocument.Parse(string); From 2273cf462b7539298871753e5a4dfac2d61e2215 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Mon, 6 Jan 2020 11:25:21 -0800 Subject: [PATCH 49/74] more api ref links --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index 1983e7c2be7ed..1f9a80dc67f20 100644 --- 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 @@ -158,9 +158,9 @@ To make deserialization fail if no `Date` property is in the JSON, implement a c Register this custom converter by [using an attribute](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-type) on the POCO class 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 `Serialize` or `Deserialize`. The options object contains the `Converters` 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. +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]`) 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: +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`. From 0890e2eba2209ab01f6910dd95c132338a9da466 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 7 Jan 2020 14:12:07 -0800 Subject: [PATCH 50/74] strings in quotes, nonstring values, polymorphism --- .../serialization/system-text-json-how-to.md | 31 +++++++++-- ...ext-json-migrate-from-newtonsoft-how-to.md | 53 ++++++++++++++++++- 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index 8aaf2d6c90f37..644b496a4d2e9 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -475,7 +475,7 @@ In this scenario, the `WindSpeed` property is not serialized even if the `weathe This behavior is intended to help prevent accidental exposure of data in a derived runtime-created type. -To serialize the properties of the derived type, use one of the following approaches: +To serialize the properties of the derived type in the preceding example, use one of the following approaches: * Call an overload of that lets you specify the type at runtime: @@ -487,16 +487,41 @@ 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] +> Polymorphic serialization is supported only for the root object to be serialized, not for properties of that root object. + +It's not possible to call `GetType` for lower-level objects, but you can get polymorphic serialization for them 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 serialization includes `WindSpeed` **only if `PreviousForecast` is defined as `Object`**: + ```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" + } } ``` -This section shows how to do **serialization**. For information about polymorphic **deserialization**, see [How to migrate from Newtonsoft.Json to System.Text.Json](system-text-json-migrate-from-newtonsoft-how-to.md#polymorphic-deserialization). +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 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 index 1f9a80dc67f20..50eaa30d84f9f 100644 --- 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 @@ -57,7 +57,51 @@ During deserialization, `Newtonsoft.Json` accepts property names surrounded by d } ``` -`System.Text.Json` only accepts names in double quotes because that format is required by the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification. +`System.Text.Json` only accepts names 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.. + +### String values + +During deserialization, `Newtonsoft.Json` accepts string values surrounded by double quotes or single quotes. For example: + +```json +{ + "name1": "value", + "name2': 'value' +} +``` + +`System.Text.Json` only accepts strings in double quotes because that format is required by the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification. 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. For example, 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 @@ -133,6 +177,12 @@ To support a dictionary with an integer or some other type as the key, create a ### Polymorphic deserialization +`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 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 [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). @@ -358,6 +408,7 @@ The DOM can't add, remove, or modify JSON elements. It's * 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, see [this GitHub issue](https://github.com/dotnet/corefx/issues/42466#issuecomment-570475853). ### JsonElement From 5a0b857cd9fafd3e4f640943665dde49acd73380 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 7 Jan 2020 14:58:56 -0800 Subject: [PATCH 51/74] corrections to polymorphic sections --- .../serialization/system-text-json-how-to.md | 13 ++++++++++--- ...stem-text-json-migrate-from-newtonsoft-how-to.md | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index 644b496a4d2e9..2cbe412631071 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -497,15 +497,22 @@ In the preceding example scenario, both approaches cause the `WindSpeed` propert ``` > [!IMPORTANT] -> Polymorphic serialization is supported only for the root object to be serialized, not for properties of that root object. +> These approaches provide polymorphic serialization only for the root object to be serialized, not for properties of that root object. -It's not possible to call `GetType` for lower-level objects, but you can get polymorphic serialization for them 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`: +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 serialization includes `WindSpeed` **only if `PreviousForecast` is defined as `Object`**: +If the `PreviousForecast` property contains an instance of `WeatherForecastDerived`: + +* The JSON output from serializing `WeatherForecastWithPreview` doesn't include `WindSpeed`. +* The JSON output from serializing `WeatherForecastWithPreviewAsObject` 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: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/SerializePolymorphic.cs?name=SnippetSerializeGetTypeSecondLevel)] ```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 index 50eaa30d84f9f..d7853433d1540 100644 --- 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 @@ -175,9 +175,9 @@ Register this custom converter by [using an attribute](system-text-json-converte 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 deserialization +### 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). +`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 like the example in [How to write custom converters](system-text-json-converters-how-to.md#support-polymorphic-deserialization). From b721d7b94ff500336359e30a6a5994be7fce6b3b Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 7 Jan 2020 15:23:27 -0800 Subject: [PATCH 52/74] address feedback --- ...ext-json-migrate-from-newtonsoft-how-to.md | 29 +++++++------------ 1 file changed, 10 insertions(+), 19 deletions(-) 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 index d7853433d1540..e1fd498cd0b81 100644 --- 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 @@ -45,32 +45,21 @@ During deserialization, `Newtonsoft.Json` ignores comments in the JSON by defaul 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 include them. For information about how to allow trailing commas, 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. -### Property names +### JSON strings -During deserialization, `Newtonsoft.Json` accepts property names surrounded by double quotes, single quotes, or without quotes. For example: +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:For example: ```json { "name1": "value", 'name2': "value", - name3: "value" + name3: 'value' } ``` -`System.Text.Json` only accepts names 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.. +`System.Text.Json` only accepts 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. -### String values - -During deserialization, `Newtonsoft.Json` accepts string values surrounded by double quotes or single quotes. For example: - -```json -{ - "name1": "value", - "name2': 'value' -} -``` - -`System.Text.Json` only accepts strings in double quotes because that format is required by the [RFC 8259](https://tools.ietf.org/html/rfc8259) specification. A value enclosed in single quotes results in a [JsonException](xref:System.Text.Json.JsonException) with the following message: +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. @@ -179,7 +168,7 @@ To support a dictionary with an integer or some other type as the key, create a `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 like the example in [How to write custom converters](system-text-json-converters-how-to.md#support-polymorphic-deserialization). +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` for the whole type like the example in [How to write custom converters](system-text-json-converters-how-to.md#support-polymorphic-deserialization). ### Polymorphic deserialization @@ -400,7 +389,9 @@ During deserialization, `Newtonsoft.Json` adds objects to a collection even if t ### 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. +`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. Otherwise, return a Cloned JsonElement. + + ### Read-only @@ -408,7 +399,7 @@ The DOM can't add, remove, or modify JSON elements. It's * 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, see [this GitHub issue](https://github.com/dotnet/corefx/issues/42466#issuecomment-570475853). +* 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 From f6b0a557f5618f6be3af8342189d5fb8d84d099e Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 7 Jan 2020 15:47:06 -0800 Subject: [PATCH 53/74] more feedback --- .../system-text-json-converters-how-to.md | 2 +- ...stem-text-json-migrate-from-newtonsoft-how-to.md | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) 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 2fc96f4a87daa..f272b111256b4 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -245,7 +245,7 @@ The [unit tests folder](https://github.com/dotnet/corefx/blob/f77914d4c9045a01b3 ### Support polymorphic deserialization -[Polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes) doesn't require a custom converter, but deserialization does require a custom converter. +Built-in features provide a limited range of [polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes) but not deserialization. Deserialization requires a custom converter. Suppose, for example, you have a `Person` abstract base class, with `Employee` and `Customer` derived classes. Polymorphic deserialization means that at design time you can specify `Person` as the deserialization target, and `Customer` and `Employee` objects in the JSON are correctly deserialized at runtime. During deserialization, you have to find clues that identify the required type in the JSON. The kinds of clues available vary with each scenario. For example, a discriminator property might be available or you might have to rely on the presence or absence of a particular property. The current release of `System.Text.Json` doesn't provide attributes to specify how to handle polymorphic deserialization scenarios, so custom converters are required. 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 index e1fd498cd0b81..424e0da8ab0ae 100644 --- 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 @@ -45,9 +45,9 @@ During deserialization, `Newtonsoft.Json` ignores comments in the JSON by defaul 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 include them. For information about how to allow trailing commas, 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 +### 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:For example: +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: ```json { @@ -57,7 +57,7 @@ During deserialization, `Newtonsoft.Json` accepts property names surrounded by d } ``` -`System.Text.Json` only accepts 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. +`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: @@ -168,11 +168,11 @@ To support a dictionary with an integer or some other type as the key, create a `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` for the whole type like the example in [How to write custom converters](system-text-json-converters-how-to.md#support-polymorphic-deserialization). +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 [polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes) but not 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 at all. 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). @@ -389,8 +389,7 @@ During deserialization, `Newtonsoft.Json` adds objects to a collection even if t ### 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. Otherwise, return a Cloned JsonElement. - +`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. Otherwise, return the `Clone` of the `RootElement`, which is a `JsonElement`. ### Read-only From 26930e846e6b30d148f0559fde03d3b31e4265d6 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 7 Jan 2020 15:57:04 -0800 Subject: [PATCH 54/74] minor wording change --- .../serialization/system-text-json-converters-how-to.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 f272b111256b4..07463444f07c8 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -245,7 +245,7 @@ The [unit tests folder](https://github.com/dotnet/corefx/blob/f77914d4c9045a01b3 ### Support polymorphic deserialization -Built-in features provide a limited range of [polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes) but not deserialization. Deserialization requires a custom converter. +Built-in features provide a limited range of [polymorphic serialization](system-text-json-how-to.md#serialize-properties-of-derived-classes) but no support for deserialization at all. Deserialization requires a custom converter. Suppose, for example, you have a `Person` abstract base class, with `Employee` and `Customer` derived classes. Polymorphic deserialization means that at design time you can specify `Person` as the deserialization target, and `Customer` and `Employee` objects in the JSON are correctly deserialized at runtime. During deserialization, you have to find clues that identify the required type in the JSON. The kinds of clues available vary with each scenario. For example, a discriminator property might be available or you might have to rely on the presence or absence of a particular property. The current release of `System.Text.Json` doesn't provide attributes to specify how to handle polymorphic deserialization scenarios, so custom converters are required. From b68ba5e77cf93ff7720e62cd96567ebe8affc737 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 7 Jan 2020 16:16:26 -0800 Subject: [PATCH 55/74] misc feedback --- ...stem-text-json-migrate-from-newtonsoft-how-to.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) 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 index 424e0da8ab0ae..1676a95983f14 100644 --- 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 @@ -24,8 +24,8 @@ Most of this article is about how to use the collection. -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: +**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)] @@ -391,7 +391,6 @@ During deserialization, `Newtonsoft.Json` adds objects to a collection even if t `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. Otherwise, return the `Clone` of the `RootElement`, which is a `JsonElement`. - ### 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 writable/modifiable DOM, one of the following workarounds might be feasible: @@ -413,7 +412,7 @@ Searches for JSON tokens using `JObject` or `JArray` from `Newtonsoft.Json` tend For a code example, see [Use JsonDocument for access to data](system-text-json-how-to.md#use-jsondocument-for-access-to-data). -## Utf8JsonReader +## Utf8JsonReader compared to JsonTextReader 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. @@ -495,7 +494,7 @@ If you need to continue to use `Newtonsoft.Json` for certain target frameworks, * [UnifiedJsonReader.JsonTextReader.cs](https://github.com/dotnet/runtime/blob/35fe82c2e90fa345d0b6ad243c14da193fb123fd/src/installer/managed/Microsoft.Extensions.DependencyModel/UnifiedJsonReader.JsonTextReader.cs) * [UnifiedJsonReader.Utf8JsonReader.cs](https://github.com/dotnet/runtime/blob/35fe82c2e90fa345d0b6ad243c14da193fb123fd/src/installer/managed/Microsoft.Extensions.DependencyModel/UnifiedJsonReader.Utf8JsonReader.cs) -## Utf8JsonWriter +## 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. @@ -532,7 +531,7 @@ If you need to continue to use `Newtonsoft.Json` for certain target frameworks, ## 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) From 80ed897574135d2eca1a584ddbd0c4488b491685 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 7 Jan 2020 20:01:16 -0800 Subject: [PATCH 56/74] misc feedback --- .../serialization/system-text-json-how-to.md | 34 ++++++++++++++++--- ...ext-json-migrate-from-newtonsoft-how-to.md | 4 +-- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index 2cbe412631071..136fbc3134644 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -155,7 +155,7 @@ To deserialize from UTF-8, call a type itself. + +For example, suppose you have a `WeatherForecast` class and a derived class `WeatherForecastDerived`: [!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecast.cs?name=SnippetWF)] @@ -507,12 +509,12 @@ You can get polymorphic serialization for lower-level objects if you define them If the `PreviousForecast` property contains an instance of `WeatherForecastDerived`: -* The JSON output from serializing `WeatherForecastWithPreview` doesn't include `WindSpeed`. -* The JSON output from serializing `WeatherForecastWithPreviewAsObject` includes `WindSpeed`. +* 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: -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/SerializePolymorphic.cs?name=SnippetSerializeGetTypeSecondLevel)] +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/SerializePolymorphic.cs?name=SnippetSerializeSecondLevel)] ```json { @@ -528,6 +530,28 @@ To serialize `WeatherForecastWithPreviousAsObject`, it isn't necessary to call ` } ``` +The same approach of defining properties as Object works with interfaces. Suppose you have the following interface, implementation, and class that you want to serialize: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/IMyInterface.cs)] + +When you serialize an instance of `PolymorphicTestInterface`, only the property defined as `Object` shows both properties of the interface implementation: + +[!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 +{ + "MyInterface": { + "Count": 5 + }, + "MyObject": { + "Count": 5, + "Name": "Implementation" + } +} +``` + 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 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 index 1676a95983f14..2dcb2a0e0111e 100644 --- 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 @@ -128,7 +128,7 @@ To implement type inference for `Object` properties, create a converter like the ### Maximum depth -`Newtonsoft.Json` doesn't have a maximum depth limit. For there's a default limit of 64, and it's configurable by setting (xref:System.Text.Json.JsonSerializerOptions.MaxDepth?displayProperty=nameWithType). +`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 (xref:System.Text.Json.JsonSerializerOptions.MaxDepth?displayProperty=nameWithType). ### Stack type handling @@ -389,7 +389,7 @@ During deserialization, `Newtonsoft.Json` adds objects to a collection even if t ### 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. Otherwise, return the `Clone` of the `RootElement`, which is a `JsonElement`. +`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. Otherwise, return the of the , which is a `JsonElement`. ### Read-only From c2191e60a1b277ec0feb225a234f6d15cc805943 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Wed, 8 Jan 2020 08:12:12 -0800 Subject: [PATCH 57/74] revise polymorphic interface example --- .../serialization/system-text-json-how-to.md | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index 136fbc3134644..be19b6d476a7f 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -530,11 +530,11 @@ To serialize `WeatherForecastWithPreviousAsObject`, it isn't necessary to call ` } ``` -The same approach of defining properties as Object works with interfaces. Suppose you have the following interface, implementation, and class that you want to serialize: +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/IMyInterface.cs)] +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/IForecast.cs)] -When you serialize an instance of `PolymorphicTestInterface`, only the property defined as `Object` shows both properties of the interface implementation: +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)] @@ -542,12 +542,16 @@ The following example shows the JSON that results from the preceding code: ```json { - "MyInterface": { - "Count": 5 + "Monday": { + "Date": "2020-01-06T00:00:00-08:00", + "TemperatureCelsius": 10, + "Summary": "Cool" }, - "MyObject": { - "Count": 5, - "Name": "Implementation" + "Tuesday": { + "Date": "2020-01-07T00:00:00-08:00", + "TemperatureCelsius": 11, + "Summary": "Rainy", + "WindSpeed": 10 } } ``` From 43a657a672c3fa720128ded9d8f12f57c3e7b69b Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Wed, 8 Jan 2020 11:43:46 -0800 Subject: [PATCH 58/74] misc feedback --- .../system-text-json-converters-how-to.md | 26 +++--- .../serialization/system-text-json-how-to.md | 8 +- ...ext-json-migrate-from-newtonsoft-how-to.md | 91 +++++++++++-------- 3 files changed, 70 insertions(+), 55 deletions(-) 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 07463444f07c8..80be48a059526 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -65,7 +65,7 @@ The following steps explain how to create a converter by following the basic pat * 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 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/runtime/tree/f77914d4c9045a01b3a91b63c28805f24850c274/src/libraries/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 @@ -191,7 +191,7 @@ 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: @@ -221,7 +221,7 @@ The following code shows a custom converter that works with `Dictionary converter that accepts external data](https://github.com/dotnet/runtime/blob/f77914d4c9045a01b3a91b63c28805f24850c274/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/f77914d4c9045a01b3a91b63c28805f24850c274/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Array.cs) +* [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/f77914d4c9045a01b3a91b63c28805f24850c274/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters) to serve as a starting point for customization. +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/f77914d4c9045a01b3a91b63c28805f24850c274/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/) +* [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) * [How to use System.Text.Json](system-text-json-how-to.md) diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index be19b6d476a7f..b2510dc0f534a 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -685,7 +685,7 @@ Null values in the JSON are ignored only if they are valid. Null values for non- ## Utf8JsonReader, Utf8JsonWriter, and JsonDocument - 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. @@ -754,14 +754,16 @@ 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'": 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 index 2dcb2a0e0111e..112f00decf905 100644 --- 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 @@ -35,7 +35,7 @@ Most of this article is about how to use 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 case-insensitive setting when it uses `System.Text.Json`. +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 @@ -134,6 +134,10 @@ To implement type inference for `Object` properties, create a converter like the In , properties of type and don't have the same value after making a round trip to and from JSON. The order of a stack's contents is reversed when it's serialized. 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). @@ -387,11 +391,11 @@ During deserialization, `Newtonsoft.Json` adds objects to a collection even if t 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. -### IDisposable +### 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. Otherwise, return the of the , which is a `JsonElement`. -### Read-only +### 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 writable/modifiable DOM, one of the following workarounds might be feasible: @@ -399,11 +403,11 @@ The DOM can't add, remove, or modify JSON elements. It's * 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 +### 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. -### Search a JsonDocument +### 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 look-ups 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 look-up time. Therefore, use the following approaches to optimize performance when searching through a `JsonDocument` object: @@ -414,76 +418,85 @@ For a code example, see [Use JsonDocument for access to data](system-text-json-h ## Utf8JsonReader compared to JsonTextReader - 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. + 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`. 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`. ### Ref struct -The `Utf8JsonReader` type is a *ref struct*, which means it has certain limitations. 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 `Span`, which itself is a ref struct. In addition, this type is mutable since it holds state. Therefore, you should **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). +The `Utf8JsonReader` type is a *ref struct*, which means 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 and write with UTF-8 text +### 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` or `ReadOnlySequence` (which is the result of reading from a `PipeReader`). 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), you should use the `Encoding.UTF8.GetBytes` API to first transcode the string to a UTF-8 encoded byte array. Then pass that to the `Utf8JsonReader`. For code examples, see [Use Utf8JsonReader](system-text-json-how-to.md#use-utf8jsonreader). +The `Utf8JsonReader` supports reading from a UTF-8 encoded [ReadOnlySpan\](xref:System.ReadOnlySpan%601) or [ReadOnlySequence\](xref:System.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`, 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` (which is the result of reading from a `PipeReader`), some JSON elements might straddle multiple segments of the `ReadOnlySequence` object. These elements would not be accessible from `ValueSpan` in a contiguous memory block. Instead, whenever you have a multi-segment `ReadOnlySequence` as input, you should always poll the `HasValueSequence` property on the reader to figure out how to access the current JSON element. Here's a recommended pattern: +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.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; - // ... - } + switch (reader.TokenType) + { + // ... + ReadOnlySpan jsonElement = reader.HasValueSequence ? + reader.ValueSequence.ToArray() : + reader.ValueSpan; + // ... + } } ``` -### Read null values +### 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: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/Utf8ReaderFromFile.cs?highlight=10,37)] + +### Read null values into nullable value types -Code that uses the `Newtonsoft.Json` reader can compare a value token type of String to null, as in the following example: +`Newtonsoft.Json` provides APIs like `ReadAsBoolean`, which handle 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 static string ReadAsString(this JsonTextReader reader) +public bool? ReadAsNullableBoolean() { - reader.Read(); - - if (reader.TokenType != JsonToken.String) + _reader.Read(); + if (_reader.TokenType == JsonTokenType.Null) { - throw new InvalidDataException(); + return null; } - - return reader.Value?.ToString(); + if (_reader.TokenType != JsonTokenType.True && _reader.TokenType != JsonTokenType.False) + { + throw CreateUnexpectedException(ref _reader, "a JSON true or false literal token"); + } + return _reader.GetBoolean(); } ``` -This code doesn't work correctly in , which considers the `null` literal to be its own token type. When using `Utf8JsonReader`, check for the `JsonTokenType.Null` token type, as shown in the following example: - ```csharp -public static string ReadAsString(this ref Utf8JsonReader reader) +public bool ReadAsBoolean(bool defaultValue) { - reader.Read(); - - if (reader.TokenType == JsonTokenType.Null) + _reader.Read(); + if (_reader.TokenType == JsonTokenType.Null) { - return null; + return defaultValue; } - - if (reader.TokenType != JsonTokenType.String) + if (_reader.TokenType != JsonTokenType.True && _reader.TokenType != JsonTokenType.False) { - throw new InvalidDataException(); + throw CreateUnexpectedException(ref _reader, "a JSON true or false literal token"); } - - return reader.GetString(); + return _reader.GetBoolean(); } ``` From 7b53d916751327741932b5a80cb692840f509a22 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Wed, 8 Jan 2020 11:52:27 -0800 Subject: [PATCH 59/74] fix links --- docs/standard/serialization/system-text-json-how-to.md | 1 - .../system-text-json-migrate-from-newtonsoft-how-to.md | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index b2510dc0f534a..f1b9ee785147e 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -764,7 +764,6 @@ The preceding code: 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'": [!code-json[](~/samples/snippets/core/system-text-json/csharp/Universities.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 index 112f00decf905..3dda2c55a09ec 100644 --- 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 @@ -418,7 +418,7 @@ For a code example, see [Use JsonDocument for access to data](system-text-json-h ## 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`. The `Utf8JsonReader` is a low-level type that can be used to build custom parsers and deserializers. + 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`. @@ -432,7 +432,7 @@ To achieve the best possible performance while using the `Utf8JsonReader`, read ### Read with a Stream or PipeReader -The `Utf8JsonReader` supports reading from a UTF-8 encoded [ReadOnlySpan\](xref:System.ReadOnlySpan%601) or [ReadOnlySequence\](xref:System.ReadOnlySequence%601) (which is the result of reading from a ). +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`. @@ -442,7 +442,7 @@ For code examples, see [Use Utf8JsonReader](system-text-json-how-to.md#use-utf8j ### 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.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: +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()) From fd056488e620c5c91377b03dffff0d8431a63210 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Wed, 8 Jan 2020 12:49:41 -0800 Subject: [PATCH 60/74] standardize links to source code --- .../system-text-json-converters-how-to.md | 4 ++-- .../serialization/system-text-json-how-to.md | 2 +- ...text-json-migrate-from-newtonsoft-how-to.md | 18 +++++++++--------- .../serialization/system-text-json-overview.md | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) 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 80be48a059526..a90c47646a0b1 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -209,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/corefx/blob/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/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. ### Support Dictionary with non-string key @@ -299,4 +299,4 @@ If you need to make a converter that modifies the behavior of an existing built- * [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 f1b9ee785147e..196d358cdaf28 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -775,4 +775,4 @@ Here's a JSON sample that the preceding code can read. The resulting summary mes * [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) * [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 index 3dda2c55a09ec..537590bffff82 100644 --- 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 @@ -16,7 +16,7 @@ This article shows how to migrate from [Newtonsoft.Json](https://www.newtonsoft. `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: @@ -256,7 +256,7 @@ And here's a converter that serializes and deserializes this struct: 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/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterKeyValuePair.cs). +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 @@ -502,10 +502,10 @@ public bool ReadAsBoolean(bool defaultValue) ### 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 [.NET Core installer](https://github.com/dotnet/runtime/tree/master/src/installer) follows: +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 [.NET Core installer](https://github.com/dotnet/runtime/tree/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/installer) follows: -* [UnifiedJsonReader.JsonTextReader.cs](https://github.com/dotnet/runtime/blob/35fe82c2e90fa345d0b6ad243c14da193fb123fd/src/installer/managed/Microsoft.Extensions.DependencyModel/UnifiedJsonReader.JsonTextReader.cs) -* [UnifiedJsonReader.Utf8JsonReader.cs](https://github.com/dotnet/runtime/blob/35fe82c2e90fa345d0b6ad243c14da193fb123fd/src/installer/managed/Microsoft.Extensions.DependencyModel/UnifiedJsonReader.Utf8JsonReader.cs) +* [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 @@ -537,14 +537,14 @@ For a string property, if the string is null, + * [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) diff --git a/docs/standard/serialization/system-text-json-overview.md b/docs/standard/serialization/system-text-json-overview.md index eec9a1e2939b0..606ee41ee4beb 100644 --- a/docs/standard/serialization/system-text-json-overview.md +++ b/docs/standard/serialization/system-text-json-overview.md @@ -29,7 +29,7 @@ The library also provides classes for working with an in-memory document object * [How to use the library](system-text-json-how-to.md) * [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/master/src/libraries/System.Text.Json) +* [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) - + From 303d8e5219078d947d39dacc6bca51ced8a54b34 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Wed, 8 Jan 2020 13:42:35 -0800 Subject: [PATCH 61/74] shorten valuetextequals example --- ...tem-text-json-migrate-from-newtonsoft-how-to.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) 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 index 537590bffff82..cf27a22306ad6 100644 --- 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 @@ -134,7 +134,7 @@ To implement type inference for `Object` properties, create a converter like the In , properties of type and don't have the same value after making a round trip to and from JSON. The order of a stack's contents is reversed when it's serialized. A custom converter could be implemented to keep stack contents in the same order. -## Omit null-value properties +### 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 . @@ -460,13 +460,15 @@ while (reader.Read()) ### 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: +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/Utf8ReaderFromFile.cs?highlight=10,37)] +[!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 like `ReadAsBoolean`, which handle 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: +`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() @@ -478,7 +480,7 @@ public bool? ReadAsNullableBoolean() } if (_reader.TokenType != JsonTokenType.True && _reader.TokenType != JsonTokenType.False) { - throw CreateUnexpectedException(ref _reader, "a JSON true or false literal token"); + throw new JsonException(); } return _reader.GetBoolean(); } @@ -494,7 +496,7 @@ public bool ReadAsBoolean(bool defaultValue) } if (_reader.TokenType != JsonTokenType.True && _reader.TokenType != JsonTokenType.False) { - throw CreateUnexpectedException(ref _reader, "a JSON true or false literal token"); + throw new JsonException(); } return _reader.GetBoolean(); } From 63e02ab472220a1aec37d318beb6bd71a5d520de Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Wed, 8 Jan 2020 15:40:15 -0800 Subject: [PATCH 62/74] misc feedback --- .../serialization/system-text-json-converters-how-to.md | 4 ++-- docs/standard/serialization/system-text-json-how-to.md | 2 +- .../system-text-json-migrate-from-newtonsoft-how-to.md | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) 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 a90c47646a0b1..23eee15c03151 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -209,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/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/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 @@ -241,7 +241,7 @@ The JSON output from serialization looks like the following example: } ``` -The [unit tests folder](https://github.com/dotnet/corefx/blob/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/System.Text.Json/tests/Serialization/) in the `System.Text.Json.Serialization` namespace has more examples of custom converters that handle non-string-key dictionaries. +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 non-string-key dictionaries. ### Support polymorphic deserialization diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index 196d358cdaf28..984469c814a0a 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -755,7 +755,7 @@ 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". +* 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 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 index cf27a22306ad6..d367ed739669b 100644 --- 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 @@ -460,7 +460,7 @@ while (reader.Read()) ### 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": +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)] @@ -504,7 +504,7 @@ public bool ReadAsBoolean(bool defaultValue) ### 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 [.NET Core installer](https://github.com/dotnet/runtime/tree/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/installer) follows: +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/) 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) @@ -539,14 +539,14 @@ For a string property, if the string is null, + * [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) From 65be13773b5728409756a76361bedf084d6b1520 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Thu, 9 Jan 2020 10:27:06 -0800 Subject: [PATCH 63/74] misc feedback --- ...ext-json-migrate-from-newtonsoft-how-to.md | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) 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 index d367ed739669b..0bf7abb698b6c 100644 --- 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 @@ -504,7 +504,7 @@ public bool ReadAsBoolean(bool defaultValue) ### 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/) library follows: +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) @@ -519,7 +519,7 @@ The following sections explain recommended programming patterns for using `Utf8J 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. For example, if you're writing string literals, consider caching them as static byte arrays, and write those instead. -### WriteRawValue +### 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: @@ -528,6 +528,21 @@ 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) - 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) - What character to use for indentation. `Utf8JsonWriter` always uses whitespace. +[QuoteChar](https://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_JsonTextWriter_QuoteChar.htm) - What 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) - Whether or not to surround property names with quotes. `Utf8JsonWriter` always uses 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: @@ -537,9 +552,13 @@ To write null values by using `Utf8JsonWriter`, call: 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/) library follows: +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) From 72a8a34c55cc568a359e81c402d838ec506dfa1e Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Thu, 9 Jan 2020 19:34:27 -0800 Subject: [PATCH 64/74] valuetuple --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 1 + 1 file changed, 1 insertion(+) 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 index 0bf7abb698b6c..c8627afce4179 100644 --- 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 @@ -335,6 +335,7 @@ Workarounds are possible for the following scenarios, but some of them would be * * * +* and its associated generic types Custom converters can be implemented for types that don't have built-in support. From 50b35745b1b2142e879d8764c3b0dbce5f7d6cd2 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Thu, 9 Jan 2020 19:38:00 -0800 Subject: [PATCH 65/74] invitation to share workaround code --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 2 ++ 1 file changed, 2 insertions(+) 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 index c8627afce4179..701d43d2c0926 100644 --- 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 @@ -322,6 +322,8 @@ If you use a custom converter that follows the preceding sample: Workarounds are possible for the following scenarios, but some of them would be relatively difficult to implement. Code samples for workarounds are not available for these scenarios. +If you implement a workaround for one of these scenarios and can share the code, select the button at the bottom of the page to send feedback for **This 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: From fd6126114bf938d35212de4695872f66cb846408 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Thu, 9 Jan 2020 20:40:28 -0800 Subject: [PATCH 66/74] feedback --- ...m-text-json-migrate-from-newtonsoft-how-to.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) 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 index 701d43d2c0926..1ba2a074b3716 100644 --- 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 @@ -520,11 +520,13 @@ The following sections explain recommended programming patterns for using `Utf8J ### 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. For example, if you're writing string literals, consider caching them as static byte arrays, and write those instead. +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` which uses your `JavascriptEncoder` do to 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: +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); @@ -533,16 +535,16 @@ 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). +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) - 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) - What character to use for indentation. `Utf8JsonWriter` always uses whitespace. -[QuoteChar](https://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_JsonTextWriter_QuoteChar.htm) - What 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) - Whether or not to surround property names with quotes. `Utf8JsonWriter` always uses quotes. +* [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. From 942e7c2ad00b906091164945e6393ab10fea59dc Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Fri, 10 Jan 2020 09:58:45 -0800 Subject: [PATCH 67/74] proofread pass --- .../system-text-json-converters-how-to.md | 14 ++-- .../serialization/system-text-json-how-to.md | 12 ++-- ...ext-json-migrate-from-newtonsoft-how-to.md | 68 ++++++++++--------- 3 files changed, 50 insertions(+), 44 deletions(-) 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 23eee15c03151..8dd41f181a578 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -20,7 +20,7 @@ A *converter* is a class that converts an object or a value to and from JSON. Th 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). @@ -168,17 +168,17 @@ 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 without a decimal to `long` @@ -193,7 +193,7 @@ The following code registers the converter: [!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)] @@ -209,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/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. +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 diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index 984469c814a0a..8e7c6a8c5ef92 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -453,7 +453,7 @@ To minimize escaping you can use type itself. +Serialization of a polymorphic type hierarchy is not supported. For example, if a property is defined as an interface or an abstract class, only the properties defined on the interface or abstract class are serialized, even if the runtime type has additional properties. The exceptions to this behavior are explained in this section. For example, suppose you have a `WeatherForecast` class and a derived class `WeatherForecastDerived`: @@ -501,7 +501,7 @@ In the preceding example scenario, both approaches cause the `WindSpeed` propert > [!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`: +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)] @@ -512,10 +512,12 @@ If the `PreviousForecast` property contains an instance of `WeatherForecastDeriv * 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: +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", @@ -530,11 +532,11 @@ To serialize `WeatherForecastWithPreviousAsObject`, it isn't necessary to call ` } ``` -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: +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`: +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)] 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 index 1ba2a074b3716..73993a8515b78 100644 --- 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 @@ -29,7 +29,7 @@ Most of this article is about how to use the 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. + 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 @@ -43,11 +43,11 @@ During deserialization, `Newtonsoft.Json` ignores comments in the JSON by defaul ### 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 include them. For information about how to allow trailing commas, 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. +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: +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 { @@ -67,7 +67,7 @@ A value enclosed in single quotes results in a [JsonException](xref:System.Text. ### 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. For example, here's an example of JSON that Newtonsoft.Json successfully deserializes to the following class: +`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 { @@ -110,25 +110,27 @@ The registration precedence for custom converters is dif 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). +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 +### Deserialization of object properties -When `Newtonsoft.Json` deserializes to `Object` properties in POCOs or in dictionaries of type `Dictionary`, it: +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 the stored complex values as a `JObject` or `JArray`. *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. +* 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). +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 (xref:System.Text.Json.JsonSerializerOptions.MaxDepth?displayProperty=nameWithType). +`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 @@ -172,11 +174,11 @@ To support a dictionary with an integer or some other type as the key, create a `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). +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 at all. +`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). @@ -199,7 +201,7 @@ To make deserialization fail if no `Date` property is in the JSON, implement a c [!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecastRequiredPropertyConverter.cs)] -Register this custom converter by [using an attribute](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-type) on the POCO class or by [adding the converter](system-text-json-converters-how-to.md#registration-sample---converters-collection) to the collection. +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. @@ -218,13 +220,13 @@ The preceding converter code is a simplified example. Additional logic would be In the same scenario, does throw an exception. (The corresponding null handling setting is .) -If you own the target type, the easiest workaround is to make the property in question nullable (for example, change `int` to `int?`). +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](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-property) on the property or by [adding the converter](system-text-json-converters-how-to.md#registration-sample---converters-collection) to the collection. +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: @@ -267,8 +269,8 @@ The `Newtonsoft.Json` `[JsonConstructor]` attribute lets you specify which const `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` setting on `JsonSerializerSettings` lets you specify that all null-value or default-value properties should be ignored. -* The `NullValueHandling` and `DefaultValueHandling` setting on `[JsonProperty]` attribute lets you specify individual properties that should be ignored when set to null or default value. +* 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: @@ -291,7 +293,7 @@ For that functionality, you can write a custom converter. Here's a sample POCO a 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](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-type) on the class or by [adding the converter](system-text-json-converters-how-to.md#registration-sample---converters-collection) to the collection. +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: @@ -311,7 +313,7 @@ In , you can simulate callbacks by writing a custom conve [!code-csharp[](~/samples/snippets/core/system-text-json/csharp/WeatherForecastCallbacksConverter.cs)] -Register this custom converter by [using an attribute](system-text-json-converters-how-to.md#registration-sample---jsonconverter-on-a-type) on the class or by [adding the converter](system-text-json-converters-how-to.md#registration-sample---converters-collection) to the collection. +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: @@ -320,9 +322,11 @@ If you use a custom converter that follows the preceding sample: ## Scenarios that JsonSerializer currently doesn't support -Workarounds are possible for the following scenarios, but some of them would be relatively difficult to implement. Code samples for workarounds are not available for these scenarios. +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 button at the bottom of the page to send feedback for **This page**. That creates a GitHub issue and adds it to the issues that are listed at the bottom of the page. +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 @@ -355,8 +359,8 @@ By default, `Newtonsoft.Json` serializes by value. For example, if an object con `Newtonsoft.Json` has a `PreserveReferencesHandling` setting on `JsonSerializerSettings` that lets you serialize by reference: -* An id 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 id instead of property values. +* 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. @@ -372,7 +376,7 @@ By default, `Newtonsoft.Json` serializes by value. For example, if an object con ### 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 provide this functionality. +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 @@ -400,7 +404,7 @@ During deserialization, `Newtonsoft.Json` adds objects to a collection even if t ### 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 writable/modifiable DOM, one of the following workarounds might be feasible: +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`. @@ -412,10 +416,10 @@ The DOM can't add, remove, or modify JSON elements. It's ### 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 look-ups 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 look-up time. Therefore, use the following approaches to optimize performance when searching through a `JsonDocument` object: +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 do unnecessary passes over the same data. +* 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). @@ -425,9 +429,9 @@ For a code example, see [Use JsonDocument for access to data](system-text-json-h The following sections explain recommended programming patterns for using `Utf8JsonReader`. -### Ref struct +### Utf8JsonReader is a ref struct -The `Utf8JsonReader` type is a *ref struct*, which means 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). +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 @@ -471,7 +475,7 @@ Don't use to do byte-by-byte ### 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: +`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() @@ -522,7 +526,7 @@ The following sections explain recommended programming patterns for using `Utf8J 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` which uses your `JavascriptEncoder` do to 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). +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 From f6d66232e9fe429a6ac5e4157766252c5f1047be Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Fri, 10 Jan 2020 10:14:28 -0800 Subject: [PATCH 68/74] update ms.date --- .../serialization/system-text-json-converters-how-to.md | 2 +- docs/standard/serialization/system-text-json-how-to.md | 2 +- .../system-text-json-migrate-from-newtonsoft-how-to.md | 2 +- docs/standard/serialization/system-text-json-overview.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) 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 8dd41f181a578..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: "01/07/2020" +ms.date: "01/10/2020" helpviewer_keywords: - "JSON serialization" - "serializing objects" diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index 8e7c6a8c5ef92..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: "01/07/2020" +ms.date: "01/10/2020" helpviewer_keywords: - "JSON serialization" - "serializing objects" 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 index 73993a8515b78..b4dd07141b479 100644 --- 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 @@ -2,7 +2,7 @@ title: "Migrate from Newtonsoft.Json to System.Text.Json - .NET" author: tdykstra ms.author: tdykstra -ms.date: "12/20/2019" +ms.date: "01/10/2020" helpviewer_keywords: - "JSON serialization" - "serializing objects" diff --git a/docs/standard/serialization/system-text-json-overview.md b/docs/standard/serialization/system-text-json-overview.md index 606ee41ee4beb..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: "01/07/2020" +ms.date: "01/10/2020" helpviewer_keywords: - "JSON serialization" - "serializing objects" From 2fa28ee67f6eac465eb84062ad40e740ef948450 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Fri, 10 Jan 2020 12:28:15 -0800 Subject: [PATCH 69/74] tools --> APIs --- .../how-to-serialize-and-deserialize-json-data.md | 2 +- .../wcf/feature-details/stand-alone-json-serialization.md | 2 +- docs/framework/wcf/samples/json-serialization.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/framework/wcf/feature-details/how-to-serialize-and-deserialize-json-data.md b/docs/framework/wcf/feature-details/how-to-serialize-and-deserialize-json-data.md index 25b2ddc78ae55..912ab1abcffb6 100644 --- a/docs/framework/wcf/feature-details/how-to-serialize-and-deserialize-json-data.md +++ b/docs/framework/wcf/feature-details/how-to-serialize-and-deserialize-json-data.md @@ -6,7 +6,7 @@ ms.assetid: 88abc1fb-8196-4ee3-a23b-c6934144d1dd # How to use 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 an efficient data encoding format that enables fast exchanges of small amounts of data between client browsers and AJAX-enabled Web services. 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). From 27d4fd4b04389708eafaabd236357ae9bab5dfac Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Fri, 10 Jan 2020 14:48:04 -0800 Subject: [PATCH 70/74] feedback --- ...ext-json-migrate-from-newtonsoft-how-to.md | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) 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 index b4dd07141b479..2204d1cbfd9a4 100644 --- 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 @@ -114,7 +114,7 @@ For more information about custom converter registration, see [Register a custom ### 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). +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 @@ -400,7 +400,25 @@ During deserialization, `Newtonsoft.Json` adds objects to a collection even if t ### 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. Otherwise, return the of the , which is a `JsonElement`. +`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 . + +Here's an example: + +```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`. ### JsonDocument is read-only From 55ee7b7e1a6efdc3419ea787b47263cab55b25b1 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Fri, 10 Jan 2020 15:06:01 -0800 Subject: [PATCH 71/74] immutablestack --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) 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 index 2204d1cbfd9a4..21f8faad017b8 100644 --- 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 @@ -134,7 +134,14 @@ To implement type inference for `object` properties, create a converter like the ### Stack type handling -In , properties of type and don't have the same value after making a round trip to and from JSON. The order of a stack's contents is reversed when it's serialized. A custom converter could be implemented to keep stack contents in the same order. +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 From b3eb4f441d15e037741b8e6516d3362d95d2f2a6 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Fri, 10 Jan 2020 15:52:26 -0800 Subject: [PATCH 72/74] clarify when to clone --- ...stem-text-json-migrate-from-newtonsoft-how-to.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) 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 index 21f8faad017b8..487a3f93c8bd5 100644 --- 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 @@ -409,9 +409,9 @@ During deserialization, `Newtonsoft.Json` adds objects to a collection even if t `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 . +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: +Here's an example that requires you to make a `Clone`: ```csharp public JsonElement LookAndLoad(JsonElement source) @@ -427,6 +427,15 @@ public JsonElement LookAndLoad(JsonElement source) 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` that isn't owned by a `JsonDocument` and return a sub-element, it's not necessary to return a `Clone` of the sub-element. 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: From 2470d9e8b22c1224b64fb35585d4524428355a30 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Fri, 10 Jan 2020 16:04:44 -0800 Subject: [PATCH 73/74] revert change already made by 16615 --- .../how-to-serialize-and-deserialize-json-data.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/framework/wcf/feature-details/how-to-serialize-and-deserialize-json-data.md b/docs/framework/wcf/feature-details/how-to-serialize-and-deserialize-json-data.md index 912ab1abcffb6..25b2ddc78ae55 100644 --- a/docs/framework/wcf/feature-details/how-to-serialize-and-deserialize-json-data.md +++ b/docs/framework/wcf/feature-details/how-to-serialize-and-deserialize-json-data.md @@ -6,7 +6,7 @@ ms.assetid: 88abc1fb-8196-4ee3-a23b-c6934144d1dd # How to use DataContractJsonSerializer > [!NOTE] -> 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). +> 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). JSON (JavaScript Object Notation) is an efficient data encoding format that enables fast exchanges of small amounts of data between client browsers and AJAX-enabled Web services. From 30277d70c3c02c1161a60811d9bd587cb62932cc Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Sat, 11 Jan 2020 07:12:20 -0800 Subject: [PATCH 74/74] Update docs/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to.md Co-Authored-By: Ahson Khan --- .../system-text-json-migrate-from-newtonsoft-how-to.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 487a3f93c8bd5..520f01c74f6d4 100644 --- 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 @@ -427,7 +427,7 @@ public JsonElement LookAndLoad(JsonElement source) 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` that isn't owned by a `JsonDocument` and return a sub-element, it's not necessary to return a `Clone` of the sub-element. For example: +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)