From f25bc4d836bbad10f6b5603bd3c93241da9609a7 Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Mon, 30 Oct 2023 17:08:17 -0700 Subject: [PATCH 1/7] remaining stj work --- docs/core/whats-new/dotnet-8.md | 46 +---- docs/fundamentals/toc.yml | 2 + .../system-text-json/overview.md | 7 +- .../system-text-json/populate-properties.md | 3 + .../reflection-vs-source-generation.md | 78 +++++++++ .../source-generation-modes.md | 127 ++------------ .../system-text-json/source-generation.md | 160 +++++++++++++----- 7 files changed, 232 insertions(+), 191 deletions(-) create mode 100644 docs/standard/serialization/system-text-json/reflection-vs-source-generation.md diff --git a/docs/core/whats-new/dotnet-8.md b/docs/core/whats-new/dotnet-8.md index 9fc3bd062dda0..6bf341a4b6390 100644 --- a/docs/core/whats-new/dotnet-8.md +++ b/docs/core/whats-new/dotnet-8.md @@ -83,8 +83,8 @@ The serializer has built-in support for the following additional types. - The source generator now supports serializing types with [`required`](../../standard/serialization/system-text-json/required-properties.md) and [`init`](../../csharp/language-reference/keywords/init.md) properties. These were both already supported in reflection-based serialization. - Improved formatting of source-generated code. -- feature parity with . This parity lets you specify serialization configuration at compile time, which ensures that the generated `MyContext.Default` property is preconfigured with all the relevant options set. -- Additional diagnostics (such as `SYSLIB1034` and `SYSLIB1039`). +- feature parity with . For more information, see [Specify options (source generation)](../../standard/serialization/system-text-json/source-generation.md#specify-options). +- Additional diagnostics (such as [SYSLIB1034](../../fundamentals/syslib-diagnostics/syslib1034.md) and [SYSLIB1039](../../fundamentals/syslib-diagnostics/syslib1039.md)). - Don't include types of ignored or inaccessible properties. - Support for nesting `JsonSerializerContext` declarations within arbitrary type kinds. - Support for compiler-generated or *unspeakable* types in weakly typed source generation scenarios. Since compiler-generated types can't be explicitly specified by the source generator, now performs nearest-ancestor resolution at run time. This resolution determines the most appropriate supertype with which to serialize the value. @@ -111,21 +111,7 @@ The serializer has built-in support for the following additional types. ##### Chain source generators -The class includes a new property that complements the existing property. These properties are used in contract customization for chaining source generators. The addition of the new property means that you don't have to specify all chained components at one call site—they can be added after the fact. - - also lets you introspect the chain or remove components from it. The following code snippet shows an example. - -```csharp -var options = new JsonSerializerOptions -{ - TypeInfoResolver = JsonTypeInfoResolver.Combine( - ContextA.Default, ContextB.Default, ContextC.Default); -}; - -options.TypeInfoResolverChain.Count; // 3 -options.TypeInfoResolverChain.RemoveAt(0); -options.TypeInfoResolverChain.Count; // 2 -``` +The class includes a new property that complements the existing property. These properties are used in contract customization for chaining source generators. The addition of the new property means that you don't have to specify all chained components at one call site—they can be added after the fact. also lets you introspect the chain or remove components from it. For more information, see [Combine source generators](../../standard/serialization/system-text-json/source-generation.md#combine-source-generators). In addition, is now obsolete. It's been superseded by the and properties. For more information, see [SYSLIB0049](../../fundamentals/syslib-diagnostics/syslib0049.md). @@ -165,6 +151,8 @@ var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolic JsonSerializer.Serialize(new { PropertyName = "value" }, options); // { "property_name" : "value" } ``` +For more information, see [Use a built-in naming policy](../../standard/serialization/system-text-json/customize-properties.md#use-a-built-in-naming-policy). + #### Read-only properties You can now deserialize onto read-only fields or properties (that is, those that don't have a `set` accessor). @@ -214,31 +202,9 @@ For more information about the *populate* deserialization behavior, see [Populat You can now disable using the reflection-based serializer by default. This disablement is useful to avoid accidental rooting of reflection components that aren't even in use, especially in trimmed and Native AOT apps. To disable default reflection-based serialization by requiring that a argument be passed to the serialization and deserialization methods, set the `JsonSerializerIsReflectionEnabledByDefault` MSBuild property to `false` in your project file. -```xml -false -``` - -(If the property is set to `false` and you don't pass a configured argument, the `Serialize` and `Deserialize` methods throw a at run time.) - Use the new API to check the value of the feature switch. If you're a library author building on top of , you can rely on the property to configure your defaults without accidentally rooting reflection components. -```csharp -static JsonSerializerOptions GetDefaultOptions() -{ - if (JsonSerializer.IsReflectionEnabledByDefault) - { - // This branch has a dependency on DefaultJsonTypeInfo, - // but it will get trimmed away if the feature switch is disabled. - return new() - { - TypeInfoResolver = new DefaultJsonTypeInfoResolver(), - PropertyNamingPolicy = JsonNamingPolicy.KebabCaseLower, - } - } - - return new() { PropertyNamingPolicy = JsonNamingPolicy.KebabCaseLower }; -} -``` +For more information, see [Disable reflection defaults](../../standard/serialization/system-text-json/source-generation.md#disable-reflection-defaults). #### New JsonNode API methods diff --git a/docs/fundamentals/toc.yml b/docs/fundamentals/toc.yml index 75d44c68cbe12..8e8eb967aaa76 100644 --- a/docs/fundamentals/toc.yml +++ b/docs/fundamentals/toc.yml @@ -592,6 +592,8 @@ items: - name: Source generation items: - name: Reflection vs. source generation + href: ../standard/serialization/system-text-json/reflection-vs-source-generation.md + - name: Source-generation modes href: ../standard/serialization/system-text-json/source-generation-modes.md - name: Use source generation href: ../standard/serialization/system-text-json/source-generation.md diff --git a/docs/standard/serialization/system-text-json/overview.md b/docs/standard/serialization/system-text-json/overview.md index 65f5363772930..84c0f0c6c079f 100644 --- a/docs/standard/serialization/system-text-json/overview.md +++ b/docs/standard/serialization/system-text-json/overview.md @@ -3,6 +3,9 @@ title: "Serialize and deserialize JSON using C# - .NET" description: This overview describes the System.Text.Json namespace functionality for serializing to and deserializing from JSON in .NET. ms.date: 10/18/2021 no-loc: [System.Text.Json, Newtonsoft.Json] +dev_langs: + - CSharp + - VB helpviewer_keywords: - "JSON serialization" - "serializing objects" @@ -58,7 +61,9 @@ There are also extension methods for System.Text.Json on [HttpContent](xref:Syst ## Reflection vs. source generation -By default, `System.Text.Json` uses [reflection](/dotnet/csharp/advanced-topics/reflection-and-attributes/) to gather the metadata it needs to access properties of objects for serialization and deserialization *at run time*. As an alternative, `System.Text.Json` can use the C# [source generation](../../../csharp/roslyn-sdk/source-generators-overview.md) feature to improve performance, reduce private memory usage, and facilitate [assembly trimming](../../../core/deploying/trimming/trim-self-contained.md), which reduces app size. For more information, see [How to choose reflection or source generation in System.Text.Json](source-generation-modes.md). +By default, `System.Text.Json` gathers the metadata it needs to access properties of objects for serialization and deserialization *at run time* using [reflection](/dotnet/csharp/advanced-topics/reflection-and-attributes/). As an alternative, `System.Text.Json` can use the C# [source generation](../../../csharp/roslyn-sdk/source-generators-overview.md) feature to improve performance, reduce private memory usage, and facilitate [assembly trimming](../../../core/deploying/trimming/trim-self-contained.md), which reduces app size. + +For more information, see [Reflection versus source generation](reflection-vs-source-generation.md). ## Security information diff --git a/docs/standard/serialization/system-text-json/populate-properties.md b/docs/standard/serialization/system-text-json/populate-properties.md index a80f09ca488fb..6944378dbf2ed 100644 --- a/docs/standard/serialization/system-text-json/populate-properties.md +++ b/docs/standard/serialization/system-text-json/populate-properties.md @@ -42,6 +42,9 @@ Starting in .NET 8, you can change the deserialization behavior to modify (*popu A struct property must have a setter; otherwise, an is thrown at run time. +> [!NOTE] +> The populate behavior currently doesn't work for types that have a parameterized constructor. For more information, see [dotnet/runtime issue 92877](https://github.com/dotnet/runtime/issues/92877). + ### Read-only properties For populating reference properties that are mutable, since the instance that the property references isn't *replaced*, the property doesn't need to have a setter. This behavior means that deserialization can also populate *read-only* properties. diff --git a/docs/standard/serialization/system-text-json/reflection-vs-source-generation.md b/docs/standard/serialization/system-text-json/reflection-vs-source-generation.md new file mode 100644 index 0000000000000..9933447ffe9bf --- /dev/null +++ b/docs/standard/serialization/system-text-json/reflection-vs-source-generation.md @@ -0,0 +1,78 @@ +--- +title: How to choose reflection or source generation in System.Text.Json +description: "Learn how to choose reflection or source generation in System.Text.Json." +ms.date: 10/30/2023 +no-loc: [System.Text.Json] +zone_pivot_groups: dotnet-preview-version +--- + +# Reflection versus source generation in System.Text.Json + +This article explains the differences between reflection and source generation as it relates to `System.Text.Json` serialization. It also provides guidance on how to choose the best approach for your scenario. + +## Metadata collection + +To serialize or deserialize a type, needs information about how to access the members of the type. `JsonSerializer` needs the following information: + +* How to access property getters and fields for serialization. +* How to access a constructor, property setters, and fields for deserialization. +* Information about which attributes have been used to customize serialization or deserialization. +* Run-time configuration from . + +This information is referred to as *metadata*. + +## Reflection + +By default, `JsonSerializer` collects metadata at run time by using [reflection](/dotnet/csharp/advanced-topics/reflection-and-attributes/). Whenever `JsonSerializer` has to serialize or deserialize a type for the first time, it collects and caches this metadata. The metadata collection process takes time and uses memory. + +## Source generation + +As an alternative, `System.Text.Json` can use the C# [source generation](../../../csharp/roslyn-sdk/source-generators-overview.md) feature to improve performance, reduce private memory usage, and facilitate [assembly trimming](../../../core/deploying/trimming/trim-self-contained.md), which reduces app size. In addition, reflection can't be used in [Native AOT applications](../../../core/deploying/native-aot/index.md), so you must use source generation for those apps. + +Source generation can be used in two modes: + +* **Metadata collection mode** + + During compilation, System.Text.Json collects the metadata needed for serialization and generates source code files. The generated source code files are automatically compiled as an integral part of the application. + +* **Serialization optimization (fast track) mode** + + features that customize the output of serialization, such as naming policies and reference preservation, carry a performance overhead. In serialization optimization mode, System.Text.Json generates optimized code that uses [`Utf8JsonWriter`](use-utf8jsonwriter.md) directly. This optimized or *fast path* code increases serialization throughput. + +Source generation for `System.Text.Json` requires C# 9.0 or a later version. + +## Feature comparison + +Choose reflection or source-generation modes based on the following benefits that each one offers: + +:::zone pivot="dotnet-8-0" + +| Benefit | Reflection | Source generation
(Metadata collection mode) | Source generation
(Serialization optimization mode) | +|------------------------------------------------------|------------|---------------------|----------------------------| +| Simpler to code and debug. | ✔️ | ❌ | ❌ | +| Supports non-public accessors. | ✔️ | ❌ | ❌ | +| Supports all available serialization customizations. | ✔️ | ❌ | ❌ | +| Reduces start-up time. | ❌ | ✔️ | ❌ | +| Reduces private memory usage. | ❌ | ✔️ | ✔️ | +| Eliminates run-time reflection. | ❌ | ✔️ | ✔️ | +| Facilitates trim-safe app size reduction. | ❌ | ✔️ | ✔️ | +| Increases serialization throughput. | ❌ | ❌ | ✔️ | + +:::zone-end + +:::zone pivot="dotnet-7-0,dotnet-6-0" + +| Benefit | Reflection | Source generation:
Metadata collection | Source generation:
Serialization optimization | +|------------------------------------------------------|------------|---------------------|----------------------------| +| Simpler to code and debug. | ✔️ | ❌ | ❌ | +| Supports non-public accessors. | ✔️ | ❌ | ❌ | +| Supports required properties. | ✔️ | ❌ | ❌ | +| Supports init-only properties. | ✔️ | ❌ | ❌ | +| Supports all available serialization customizations. | ✔️ | ❌ | ❌ | +| Reduces start-up time. | ❌ | ✔️ | ❌ | +| Reduces private memory usage. | ❌ | ✔️ | ✔️ | +| Eliminates run-time reflection. | ❌ | ✔️ | ✔️ | +| Facilitates trim-safe app size reduction. | ❌ | ✔️ | ✔️ | +| Increases serialization throughput. | ❌ | ❌ | ✔️ | + +:::zone-end diff --git a/docs/standard/serialization/system-text-json/source-generation-modes.md b/docs/standard/serialization/system-text-json/source-generation-modes.md index be101a4b49b9c..5bcc2f7564182 100644 --- a/docs/standard/serialization/system-text-json/source-generation-modes.md +++ b/docs/standard/serialization/system-text-json/source-generation-modes.md @@ -1,7 +1,7 @@ --- -title: How to choose reflection or source generation in System.Text.Json -description: "Learn how to choose reflection or source generation in System.Text.Json." -ms.date: 09/25/2023 +title: Source-generation modes in System.Text.Json +description: Learn about the two different source-generation modes in System.Text.Json. +ms.date: 10/30/2023 no-loc: [System.Text.Json] zone_pivot_groups: dotnet-preview-version helpviewer_keywords: @@ -9,69 +9,13 @@ helpviewer_keywords: - "serializing objects" - "serialization" - "objects, serializing" -ms.topic: how-to --- -# How to choose reflection or source generation in System.Text.Json +# Source-generation modes in System.Text.Json -By default, `System.Text.Json` uses run-time reflection to gather the metadata it needs to access properties of objects for serialization and deserialization. As an alternative, `System.Text.Json` 6.0 and later can use the C# [source generation](../../../csharp/roslyn-sdk/source-generators-overview.md) feature to improve performance, reduce private memory usage, and facilitate [assembly trimming](../../../core/deploying/trimming/trim-self-contained.md), which reduces app size. +Source generation can be used in two modes: metadata collection and serialization optimization. This article describes the different modes. -You can use version 6.0+ of `System.Text.Json` in projects that target earlier frameworks. For more information, see [How to get the library](overview.md#how-to-get-the-library). - -This article explains the options and provides guidance on how to choose the best approach for your scenario. - -## Overview - -Choose reflection or source generation modes based on the following benefits that each one offers: - -:::zone pivot="dotnet-8-0" - -| Benefit | Reflection | Source generation:
Metadata collection | Source generation:
Serialization optimization | -|------------------------------------------------------|------------|---------------------|----------------------------| -| Simpler to code and debug. | ✔️ | ❌ | ❌ | -| Supports non-public accessors. | ✔️ | ❌ | ❌ | -| Supports required properties. | ✔️ | ✔️ | ✔️ | -| Supports init-only properties. | ✔️ | ✔️ | ✔️ | -| Supports all available serialization customizations. | ✔️ | ❌ | ❌ | -| Reduces start-up time. | ❌ | ✔️ | ❌ | -| Reduces private memory usage. | ❌ | ✔️ | ✔️ | -| Eliminates run-time reflection. | ❌ | ✔️ | ✔️ | -| Facilitates trim-safe app size reduction. | ❌ | ✔️ | ✔️ | -| Increases serialization throughput. | ❌ | ❌ | ✔️ | - -:::zone-end - -:::zone pivot="dotnet-7-0,dotnet-6-0" - -| Benefit | Reflection | Source generation:
Metadata collection | Source generation:
Serialization optimization | -|------------------------------------------------------|------------|---------------------|----------------------------| -| Simpler to code and debug. | ✔️ | ❌ | ❌ | -| Supports non-public accessors. | ✔️ | ❌ | ❌ | -| Supports required properties. | ✔️ | ❌ | ❌ | -| Supports init-only properties. | ✔️ | ❌ | ❌ | -| Supports all available serialization customizations. | ✔️ | ❌ | ❌ | -| Reduces start-up time. | ❌ | ✔️ | ❌ | -| Reduces private memory usage. | ❌ | ✔️ | ✔️ | -| Eliminates run-time reflection. | ❌ | ✔️ | ✔️ | -| Facilitates trim-safe app size reduction. | ❌ | ✔️ | ✔️ | -| Increases serialization throughput. | ❌ | ❌ | ✔️ | - -:::zone-end - -The following sections explain these options and their relative benefits. - -## System.Text.Json metadata - -To serialize or deserialize a type, needs information about how to access the members of the type. `JsonSerializer` needs the following information: - -* How to access property getters and fields for serialization. -* How to access a constructor, property setters, and fields for deserialization. -* Information about which attributes have been used to customize serialization or deserialization. -* Run-time configuration from . - -This information is referred to as *metadata*. - -By default, `JsonSerializer` collects metadata at run time by using [reflection](/dotnet/csharp/advanced-topics/reflection-and-attributes/). Whenever `JsonSerializer` has to serialize or deserialize a type for the first time, it collects and caches this metadata. The metadata collection process takes time and uses memory. +For information about how to use source generation modes, see [How to use source generation in System.Text.Json](source-generation.md). ## Source generation - metadata collection mode @@ -99,13 +43,15 @@ For information about other known issues with source generation, see the [GitHub `JsonSerializer` has many features that customize the output of serialization, such as [naming policies](customize-properties.md#use-a-built-in-naming-policy) and [preserving references](preserve-references.md#preserve-references-and-handle-circular-references). Support for all those features causes some performance overhead. Source generation can improve serialization performance by generating optimized code that uses [`Utf8JsonWriter`](use-utf8jsonwriter.md) directly. -The optimized code doesn't support all of the serialization features that `JsonSerializer` supports. The serializer detects whether the optimized code can be used and falls back to default serialization code if unsupported options are specified. For example, is not applicable to writing, so specifying this option doesn't cause a fall-back to default code. +The optimized code doesn't support all of the serialization features that `JsonSerializer` supports. The serializer detects whether the optimized code can be used and falls back to default serialization code if unsupported options are specified. For example, isn't applicable to writing, so specifying this option doesn't cause a fallback to default code. The following table shows which options in `JsonSerializerOptions` are supported by the optimized serialization code: | Serialization option | Supported by optimized code | |------------------------------------------------------------------------|-----------------------------| +| | ❌ | | | ❌ | +| | ❌ | | | ✔️ | | | ❌ | | | ❌ | @@ -113,16 +59,21 @@ The following table shows which options in `JsonSerializerOptions` are supported | | ✔️ | | | ✔️ | | | ✔️ | +| | ❌ | | | ❌ | +| | ❌ | | | ✔️ | +| | ❌ | | | ❌ | | | ✔️ | +| | ❌ | | | ✔️ | The following table shows which attributes are supported by the optimized serialization code: | Attribute | Supported by optimized code | |-------------------------------------------------------------------|-----------------------------| +| | ❌ | | | ❌ | | | ✔️ | | | ❌ | @@ -131,58 +82,12 @@ The following table shows which attributes are supported by the optimized serial | | ❌ | | | ✔️ | | | ✔️ | +| | ❌ | | | ✔️ | -If a non-supported option or attribute is specified for a type, the serializer falls back to the default `JsonSerializer` code. In that case, the optimized code isn't used when serializing that type but may be used for other types. Therefore it's important to do performance testing with your options and workloads to determine how much benefit you can actually get from serialization optimization mode. Also, the ability to fall back to `JsonSerializer` code requires metadata collection mode. If you select only serialization optimization mode, serialization might fail for types or options that need to fall back to `JsonSerializer` code. - -## How to use source generation modes - -Most of the System.Text.Json documentation shows how to write code that uses reflection mode. For information about how to use source generation modes, see [How to use source generation in System.Text.Json](source-generation.md). - -:::zone pivot="dotnet-8-0" - -## Serialize enum fields as strings - -### `JsonStringEnumConverter` converter - -By default, enums are serialized as numbers. To serialize enum names as strings using source generation, use the converter. (The non-generic type is not supported by the Native AOT runtime.) - -Suppose you need to serialize the following class that has an enum property: - -:::code language="csharp" source="snippets/how-to/csharp/WeatherForecast.cs" id="WFWithConverterEnum"::: - -Create a class and annotate it with the attribute: - -:::code language="csharp" source="snippets/how-to/csharp/RoundtripEnumSourceGeneration.cs" id="Context1"::: - -The following code serializes the enum names instead of the numeric values: - -:::code language="csharp" source="snippets/how-to/csharp/RoundtripEnumSourceGeneration.cs" id="Serialize"::: - -The resulting JSON looks like the following example: - -```json -{ - "Date": "2019-08-01T00:00:00-07:00", - "TemperatureCelsius": 25, - "Precipitation": "Sleet" -} -``` - -### Blanket policy - -Instead of using the type, you can apply a blanket policy to serialize enums as strings by using the . Create a class and annotate it with the *and * attributes: - -:::code language="csharp" source="snippets/how-to/csharp/RoundtripEnumSourceGeneration.cs" id="Context2"::: - -Notice that the enum doesn't have the : - -:::code language="csharp" source="snippets/how-to/csharp/WeatherForecast.cs" id="WFWithPrecipEnumNoConverter"::: - -:::zone-end +If a non-supported option or attribute is specified for a type, the serializer falls back to the default `JsonSerializer` code. In that case, the optimized code isn't used when serializing that type but may be used for other types. Therefore it's important to do performance testing with your options and workloads to determine how much benefit you can actually get from serialization-optimization mode. Also, the ability to fall back to `JsonSerializer` code requires metadata-collection mode. If you select only serialization-optimization mode, serialization might fail for types or options that need to fall back to `JsonSerializer` code. ## See also -* [Try the new System.Text.Json source generator](https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-source-generator/) * [JSON serialization and deserialization in .NET - overview](overview.md) * [How to use the library](how-to.md) diff --git a/docs/standard/serialization/system-text-json/source-generation.md b/docs/standard/serialization/system-text-json/source-generation.md index 93c4857f05a43..15cbffa19f274 100644 --- a/docs/standard/serialization/system-text-json/source-generation.md +++ b/docs/standard/serialization/system-text-json/source-generation.md @@ -17,9 +17,11 @@ ms.topic: how-to # How to use source generation in System.Text.Json -Source generation in System.Text.Json is available in .NET 6 and later versions. Source generation consists of two modes: *metadata collection* and *serialization optimization*. +Source generation in System.Text.Json is available in .NET 6 and later versions. When used in an app, the app's language version must be C# 9.0 or later. This article shows you how to use source-generation-backed serialization in your apps. -## Use source generation defaults +For information about the different source-generation modes, see [Source-generation modes](source-generation-modes.md). + +## Use source-generation defaults To use source generation with all defaults (both modes, default options): @@ -93,14 +95,14 @@ Here are the preceding examples in a complete program: :::code language="csharp" source="snippets/source-generation/csharp/BothModesNoOptions.cs" id="All"::: -## Specify source generation mode +## Specify source-generation mode -You can specify metadata collection mode or serialization optimization mode for an entire context, which may include multiple types. Or you can specify the mode for an individual type. If you do both, the mode specification for a type wins. +You can specify metadata-collection mode or serialization-optimization mode for an entire context, which may include multiple types. Or you can specify the mode for an individual type. If you do both, the mode specification for a type wins. - For an entire context, use the property. - For an individual type, use the property. -### Serialization optimization mode example +### Serialization-optimization mode example - For an entire context: @@ -114,7 +116,7 @@ You can specify metadata collection mode or serialization optimization mode for :::code language="csharp" source="snippets/source-generation/csharp/SerializeOnlyNoOptions.cs" id="All"::: -### Metadata collection mode example +### Metadata-collection mode example - For an entire context: @@ -136,9 +138,87 @@ You can specify metadata collection mode or serialization optimization mode for :::code language="csharp" source="snippets/source-generation/csharp/MetadataOnlyNoOptions.cs" id="All"::: -## Specify options for serialization optimization mode +## Source-generation support in ASP.NET Core + +In Blazor apps, use overloads of and extension methods that take a source generation context or `TypeInfo`. + +:::zone pivot="dotnet-8-0,dotnet-7-0" + +In Razor Pages, MVC, SignalR, and Web API apps, use the property to specify the context. + +```csharp +[JsonSerializable(typeof(WeatherForecast[]))] +internal partial class MyJsonContext : JsonSerializerContext { } +``` + +```csharp +var serializerOptions = new JsonSerializerOptions +{ + TypeInfoResolver = MyJsonContext.Default; +}; + +services.AddControllers().AddJsonOptions(options => + options.JsonSerializerOptions = serializerOptions); +``` + +:::zone-end + +:::zone pivot="dotnet-6-0" + +In Razor Pages, MVC, SignalR, and Web API apps, use the method of , as shown in the following example: + +```csharp +[JsonSerializable(typeof(WeatherForecast[]))] +internal partial class MyJsonContext : JsonSerializerContext { } +``` + +```csharp +services.AddControllers().AddJsonOptions(options => + options.JsonSerializerOptions.AddContext()); +``` + +:::zone-end + +:::zone pivot="dotnet-8-0" + +## Disable reflection defaults + +Because System.Text.Json uses reflection by default, calling a basic serialization method can break Native AOT apps, which can't reflect at run time. These breaks can be challenging to diagnose since apps are often debugged using the CoreCLR runtime, where the code works. Instead, if you explicitly disable reflection-based serialization, breaks are easier to diagnose. Code that uses reflection-based serialization will cause an with a descriptive message to be thrown at run time. + +To disable default reflection in your app, set the `JsonSerializerIsReflectionEnabledByDefault` MSBuild property to `false` in your project file: + +```xml + + false + +``` -Use to specify options that are supported by serialization optimization mode. You can use these options without causing a fallback to `JsonSerializer` code. For example, `WriteIndented` and `CamelCase` are supported: +- The behavior of this property is consistent regardless of runtime, either CoreCLR or Native AOT. +- If you don't specify this property and [PublishTrimmed](../../../core/project-sdk/msbuild-props.md#trim-related-properties) is enabled, reflection-based serialization is automatically disabled. + +You can programmatically check whether reflection is disabled by using the property. The following code snippet shows how you might configure your serializer depending on whether reflection is enabled: + +```csharp +static JsonSerializerOptions CreateDefaultOptions() +{ + return new() + { + TypeInfoResolver = JsonSerializer.IsReflectionEnabledByDefault + ? new DefaultJsonTypeInfoResolver() + : MyContext.Default + }; +} +``` + +Because the property is treated as a link-time constant, the previous method doesn't root the reflection-based resolver in applications that run in Native AOT. + +:::zone-end + +## Specify options + +In .NET 8 and later versions, most options that you can set using can also be set using the attribute. The advantage to setting options via the attribute is that the configuration is specified at compile time, which ensures that the generated `MyContext.Default` property is preconfigured with all the relevant options set. + +The following code shows how to set options using the xref:System.Text.Json.Serialization.JsonSourceGenerationOptionsAttribute> attribute. :::code language="csharp" source="snippets/source-generation/csharp/SerializeOnlyWithOptions.cs" id="JsonSourceGenerationOptions"::: @@ -160,11 +240,11 @@ Here are the preceding examples in a complete program: :::code language="csharp" source="snippets/source-generation/csharp/SerializeOnlyWithOptions.cs" id="All"::: -## Specify options by using `JsonSerializerOptions` +:::zone pivot="dotnet-7-0,dotnet-6-0" -Some options of aren't supported by serialization optimization mode. Such options cause a fallback to the non-source-generated `JsonSerializer` code. For more information, see [Serialization optimization](source-generation-modes.md#serialization-optimization-mode). +### Specify options by using `JsonSerializerOptions` -To specify options by using : +Some options of can't be set using . To specify options by using : - Create an instance of `JsonSerializerOptions`. - Create an instance of your class that derives from , and pass the `JsonSerializerOptions` instance to the constructor. @@ -182,6 +262,8 @@ Here are the preceding examples in a complete program: :::code language="csharp" source="snippets/source-generation/csharp/JsonSerializerOptionsExample.cs" id="All"::: +:::zone-end + :::zone pivot="dotnet-8-0,dotnet-7-0" ## Combine source generators @@ -204,51 +286,51 @@ options.TypeInfoResolverChain.Insert(0, ContextE.Default); // Insert at the begi Any change made to the property is reflected by and vice versa. -:::zone-end +:::zone pivot="dotnet-8-0" -## Source generation support in ASP.NET Core +## Serialize enum fields as strings -In Blazor apps, use overloads of and extension methods that take a source generation context or `TypeInfo`. +By default, enums are serialized as numbers. To [serialize a specific enum's fields as strings](#jsonstringenumconvertert-converter) when using source generation, annotate it with the converter. Or to set a [blanket policy](#blanket-policy) for all enumerations, use the attribute. -:::zone pivot="dotnet-8-0,dotnet-7-0" +### `JsonStringEnumConverter` converter -In Razor Pages, MVC, SignalR, and Web API apps, use the property to specify the context. +To serialize enum names as strings using source generation, use the converter. (The non-generic type is not supported by the Native AOT runtime.) -```csharp -[JsonSerializable(typeof(WeatherForecast[]))] -internal partial class MyJsonContext : JsonSerializerContext { } -``` +Annotate the enumeration type with the converter using the attribute: -```csharp -var serializerOptions = new JsonSerializerOptions -{ - TypeInfoResolver = MyJsonContext.Default; -}; +:::code language="csharp" source="snippets/how-to/csharp/WeatherForecast.cs" id="WFWithConverterEnum"::: -services.AddControllers().AddJsonOptions(options => - options.JsonSerializerOptions = serializerOptions); -``` +Create a class and annotate it with the attribute: -:::zone-end +:::code language="csharp" source="snippets/how-to/csharp/RoundtripEnumSourceGeneration.cs" id="Context1"::: -:::zone pivot="dotnet-6-0" +The following code serializes the enum names instead of the numeric values: -In Razor Pages, MVC, SignalR, and Web API apps, use the method of , as shown in the following example: +:::code language="csharp" source="snippets/how-to/csharp/RoundtripEnumSourceGeneration.cs" id="Serialize"::: -```csharp -[JsonSerializable(typeof(WeatherForecast[]))] -internal partial class MyJsonContext : JsonSerializerContext { } -``` +The resulting JSON looks like the following example: -```csharp -services.AddControllers().AddJsonOptions(options => - options.JsonSerializerOptions.AddContext()); +```json +{ + "Date": "2019-08-01T00:00:00-07:00", + "TemperatureCelsius": 25, + "Precipitation": "Sleet" +} ``` +### Blanket policy + +Instead of using the type, you can apply a blanket policy to serialize enums as strings by using the . Create a class and annotate it with the *and * attributes: + +:::code language="csharp" source="snippets/how-to/csharp/RoundtripEnumSourceGeneration.cs" id="Context2"::: + +Notice that the enum doesn't have the : + +:::code language="csharp" source="snippets/how-to/csharp/WeatherForecast.cs" id="WFWithPrecipEnumNoConverter"::: + :::zone-end ## See also -- [Try the new System.Text.Json source generator](https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-source-generator/) - [JSON serialization and deserialization in .NET - overview](overview.md) - [How to use the library](how-to.md) From 38255b87e8e4ef2eb3eaeb0670131867c4d7c29c Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Mon, 30 Oct 2023 18:05:01 -0700 Subject: [PATCH 2/7] try to fix warnings --- docs/core/whats-new/dotnet-8.md | 4 ++-- .../serialization/system-text-json/customize-properties.md | 2 +- .../serialization/system-text-json/source-generation.md | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/core/whats-new/dotnet-8.md b/docs/core/whats-new/dotnet-8.md index 6bf341a4b6390..16b7275d4931d 100644 --- a/docs/core/whats-new/dotnet-8.md +++ b/docs/core/whats-new/dotnet-8.md @@ -79,7 +79,7 @@ The serializer has built-in support for the following additional types. #### Source generator -.NET 8 includes enhancements of the System.Text.Json [source generator](../../standard/serialization/system-text-json/source-generation.md) that are aimed at making the [Native AOT](../../standard/glossary.md#native-aot) experience on par with the [reflection-based serializer](../../standard/serialization/system-text-json/source-generation-modes.md#overview). For example: +.NET 8 includes enhancements of the System.Text.Json [source generator](../../standard/serialization/system-text-json/source-generation.md) that are aimed at making the [Native AOT](../../standard/glossary.md#native-aot) experience on par with the [reflection-based serializer](../../standard/serialization/system-text-json/reflection-vs-source-generation.md#reflection). For example: - The source generator now supports serializing types with [`required`](../../standard/serialization/system-text-json/required-properties.md) and [`init`](../../csharp/language-reference/keywords/init.md) properties. These were both already supported in reflection-based serialization. - Improved formatting of source-generated code. @@ -98,7 +98,7 @@ The serializer has built-in support for the following additional types. public partial class MyContext : JsonSerializerContext { } ``` - For more information, see [Serialize enum fields as strings](../../standard/serialization/system-text-json/source-generation-modes.md#serialize-enum-fields-as-strings). + For more information, see [Serialize enum fields as strings](../../standard/serialization/system-text-json/source-generation.md#serialize-enum-fields-as-strings). - New `JsonConverter.Type` property lets you look up the type of a non-generic `JsonConverter` instance: diff --git a/docs/standard/serialization/system-text-json/customize-properties.md b/docs/standard/serialization/system-text-json/customize-properties.md index ededc79048f4a..a7fdd0dbf655c 100644 --- a/docs/standard/serialization/system-text-json/customize-properties.md +++ b/docs/standard/serialization/system-text-json/customize-properties.md @@ -218,7 +218,7 @@ The resulting JSON looks like the following example: } ``` -To use the converter with source generation, see [Serialize enum fields as strings](source-generation-modes.md#serialize-enum-fields-as-strings). +To use the converter with source generation, see [Serialize enum fields as strings](source-generation.md#serialize-enum-fields-as-strings). :::zone-end diff --git a/docs/standard/serialization/system-text-json/source-generation.md b/docs/standard/serialization/system-text-json/source-generation.md index 15cbffa19f274..aa18e17478f9a 100644 --- a/docs/standard/serialization/system-text-json/source-generation.md +++ b/docs/standard/serialization/system-text-json/source-generation.md @@ -286,6 +286,8 @@ options.TypeInfoResolverChain.Insert(0, ContextE.Default); // Insert at the begi Any change made to the property is reflected by and vice versa. +:::zone-end + :::zone pivot="dotnet-8-0" ## Serialize enum fields as strings From 9fe29f3db8e4321ade48b64183bf27c3b08e239f Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Mon, 30 Oct 2023 18:54:01 -0700 Subject: [PATCH 3/7] Apply suggestions from code review Co-authored-by: David Pine --- .../reflection-vs-source-generation.md | 4 ++-- .../system-text-json/source-generation.md | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/standard/serialization/system-text-json/reflection-vs-source-generation.md b/docs/standard/serialization/system-text-json/reflection-vs-source-generation.md index 9933447ffe9bf..2e35411acb1fc 100644 --- a/docs/standard/serialization/system-text-json/reflection-vs-source-generation.md +++ b/docs/standard/serialization/system-text-json/reflection-vs-source-generation.md @@ -23,7 +23,7 @@ This information is referred to as *metadata*. ## Reflection -By default, `JsonSerializer` collects metadata at run time by using [reflection](/dotnet/csharp/advanced-topics/reflection-and-attributes/). Whenever `JsonSerializer` has to serialize or deserialize a type for the first time, it collects and caches this metadata. The metadata collection process takes time and uses memory. +By default, collects metadata at run time by using [reflection](/dotnet/csharp/advanced-topics/reflection-and-attributes/). Whenever `JsonSerializer` has to serialize or deserialize a type for the first time, it collects and caches this metadata. The metadata collection process takes time and uses memory. ## Source generation @@ -33,7 +33,7 @@ Source generation can be used in two modes: * **Metadata collection mode** - During compilation, System.Text.Json collects the metadata needed for serialization and generates source code files. The generated source code files are automatically compiled as an integral part of the application. + During compilation, `System.Text.Json` collects the metadata needed for serialization and generates source code files. The generated source code files are automatically compiled as an integral part of the app. * **Serialization optimization (fast track) mode** diff --git a/docs/standard/serialization/system-text-json/source-generation.md b/docs/standard/serialization/system-text-json/source-generation.md index aa18e17478f9a..5a732359415e6 100644 --- a/docs/standard/serialization/system-text-json/source-generation.md +++ b/docs/standard/serialization/system-text-json/source-generation.md @@ -141,6 +141,11 @@ You can specify metadata-collection mode or serialization-optimization mode for ## Source-generation support in ASP.NET Core In Blazor apps, use overloads of and extension methods that take a source generation context or `TypeInfo`. +:::zone pivot="dotnet-8" + +Starting with .NET 8, you can also use overloads of extension methods that accept a source generation context or `TypeInfo`. + +:::zone-end :::zone pivot="dotnet-8-0,dotnet-7-0" @@ -157,8 +162,9 @@ var serializerOptions = new JsonSerializerOptions TypeInfoResolver = MyJsonContext.Default; }; -services.AddControllers().AddJsonOptions(options => - options.JsonSerializerOptions = serializerOptions); +services.AddControllers().AddJsonOptions( + static options => + options.JsonSerializerOptions = serializerOptions); ``` :::zone-end From 19e6f392abed871ba8fd0c096e882b93768060bb Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Mon, 30 Oct 2023 18:54:28 -0700 Subject: [PATCH 4/7] tweaks --- .../system-text-json/source-generation-modes.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/standard/serialization/system-text-json/source-generation-modes.md b/docs/standard/serialization/system-text-json/source-generation-modes.md index 5bcc2f7564182..f77e56712fb23 100644 --- a/docs/standard/serialization/system-text-json/source-generation-modes.md +++ b/docs/standard/serialization/system-text-json/source-generation-modes.md @@ -17,7 +17,7 @@ Source generation can be used in two modes: metadata collection and serializatio For information about how to use source generation modes, see [How to use source generation in System.Text.Json](source-generation.md). -## Source generation - metadata collection mode +## Metadata collection mode You can use source generation to move the metadata collection process from run time to compile time. During compilation, the metadata is collected and source code files are generated. The generated source code files are automatically compiled as an integral part of the application. This technique eliminates run-time metadata collection, which improves performance of both serialization and deserialization. @@ -27,13 +27,13 @@ The performance improvements provided by source generation can be substantial. F :::zone pivot="dotnet-7-0,dotnet-6-0" -Only `public` properties and fields are supported by default\* in either serialization mode. However, reflection mode supports the use of `private` *accessors*, while source-generation mode doesn't. For example, you can apply the [JsonInclude attribute](xref:System.Text.Json.Serialization.JsonIncludeAttribute) to a property that has a `private` setter or getter and it will be serialized in reflection mode. Source-generation mode supports only `public` or `internal` accessors of `public` properties. If you set `[JsonInclude]` on non-public accessors and choose source-generation mode, a `NotSupportedException` will be thrown at run time. +Only `public` properties and fields are supported by default in either serialization mode. However, reflection mode supports the use of `private` *accessors*, while source-generation mode doesn't. For example, you can apply the [JsonInclude attribute](xref:System.Text.Json.Serialization.JsonIncludeAttribute) to a property that has a `private` setter or getter and it will be serialized in reflection mode. Source-generation mode supports only `public` or `internal` accessors of `public` properties. If you set `[JsonInclude]` on non-public accessors and choose source-generation mode, a `NotSupportedException` will be thrown at run time. :::zone-end :::zone pivot="dotnet-8-0" -Only `public` properties and fields are supported by default\* in either serialization mode. However, reflection mode supports the use of `private` members and `private` *accessors*, while source-generation mode doesn't. For example, if you apply the [JsonInclude attribute](xref:System.Text.Json.Serialization.JsonIncludeAttribute) to a `private` property or a property that has a `private` setter or getter, it will be serialized in reflection mode. Source-generation mode supports only `public` or `internal` members and `public` or `internal` accessors of `public` properties. If you set `[JsonInclude]` on `private` members or accessors and choose source-generation mode, a `NotSupportedException` will be thrown at run time. +Only `public` properties and fields are supported by default in either serialization mode. However, reflection mode supports the use of `private` members and `private` *accessors*, while source-generation mode doesn't. For example, if you apply the [JsonInclude attribute](xref:System.Text.Json.Serialization.JsonIncludeAttribute) to a `private` property or a property that has a `private` setter or getter, it will be serialized in reflection mode. Source-generation mode supports only `public` or `internal` members and `public` or `internal` accessors of `public` properties. If you set `[JsonInclude]` on `private` members or accessors and choose source-generation mode, a `NotSupportedException` will be thrown at run time. :::zone-end From b9b534df4b34920a89e1696d0dc15d646134f7be Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Mon, 30 Oct 2023 19:03:07 -0700 Subject: [PATCH 5/7] fix warnings --- docs/standard/serialization/system-text-json/overview.md | 2 +- .../serialization/system-text-json/required-properties.md | 2 +- .../serialization/system-text-json/source-generation.md | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/standard/serialization/system-text-json/overview.md b/docs/standard/serialization/system-text-json/overview.md index 84c0f0c6c079f..d56fb602e1d7c 100644 --- a/docs/standard/serialization/system-text-json/overview.md +++ b/docs/standard/serialization/system-text-json/overview.md @@ -25,7 +25,7 @@ For Visual Basic, there are some limitations on what parts of the library you ca ## How to get the library -The library is built-in as part of the shared framework for .NET Core 3.0 and later versions. The [source generation feature](source-generation-modes.md#source-generation---metadata-collection-mode) is built-in as part of the shared framework for .NET 6 and later versions. Use of source generation requires .NET 5 SDK or later. +The library is built-in as part of the shared framework for .NET Core 3.0 and later versions. The [source generation feature](source-generation-modes.md#metadata-collection-mode) is built-in as part of the shared framework for .NET 6 and later versions. Use of source generation requires .NET 5 SDK or later. For framework versions earlier than .NET Core 3.0, install the [System.Text.Json](https://www.nuget.org/packages/System.Text.Json) NuGet package. The package supports: diff --git a/docs/standard/serialization/system-text-json/required-properties.md b/docs/standard/serialization/system-text-json/required-properties.md index 331a8f1827261..47b26827b46bf 100644 --- a/docs/standard/serialization/system-text-json/required-properties.md +++ b/docs/standard/serialization/system-text-json/required-properties.md @@ -18,7 +18,7 @@ From the serializer's perspective, these two demarcations are equivalent and bot - If you're using a programming language other than C# or a down-level version of C#. - If you only want the requirement to apply to JSON deserialization. -- If you're using `System.Text.Json` serialization in [source generation](source-generation-modes.md#source-generation---metadata-collection-mode) mode. In this case, your code won't compile if you use the `required` modifier, as source generation occurs at compile time. +- If you're using `System.Text.Json` serialization in [source generation](source-generation-modes.md#metadata-collection-mode) mode. In this case, your code won't compile if you use the `required` modifier, as source generation occurs at compile time. The following code snippet shows an example of a property modified with the `required` keyword. This property must be present in the JSON payload for deserialization to succeed. diff --git a/docs/standard/serialization/system-text-json/source-generation.md b/docs/standard/serialization/system-text-json/source-generation.md index 5a732359415e6..2ce6f63737da6 100644 --- a/docs/standard/serialization/system-text-json/source-generation.md +++ b/docs/standard/serialization/system-text-json/source-generation.md @@ -141,7 +141,8 @@ You can specify metadata-collection mode or serialization-optimization mode for ## Source-generation support in ASP.NET Core In Blazor apps, use overloads of and extension methods that take a source generation context or `TypeInfo`. -:::zone pivot="dotnet-8" + +:::zone pivot="dotnet-8-0" Starting with .NET 8, you can also use overloads of extension methods that accept a source generation context or `TypeInfo`. From 1e44f9932180d0db4006e1add7c637330b20075f Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Tue, 31 Oct 2023 11:27:35 -0700 Subject: [PATCH 6/7] Apply suggestions from code review Co-authored-by: Eirik Tsarpalis --- .../reflection-vs-source-generation.md | 13 ++++++------- .../system-text-json/source-generation-modes.md | 8 ++++---- .../system-text-json/source-generation.md | 2 +- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/docs/standard/serialization/system-text-json/reflection-vs-source-generation.md b/docs/standard/serialization/system-text-json/reflection-vs-source-generation.md index 2e35411acb1fc..e9ef4093785dc 100644 --- a/docs/standard/serialization/system-text-json/reflection-vs-source-generation.md +++ b/docs/standard/serialization/system-text-json/reflection-vs-source-generation.md @@ -27,15 +27,15 @@ By default, collects metadata at run time ## Source generation -As an alternative, `System.Text.Json` can use the C# [source generation](../../../csharp/roslyn-sdk/source-generators-overview.md) feature to improve performance, reduce private memory usage, and facilitate [assembly trimming](../../../core/deploying/trimming/trim-self-contained.md), which reduces app size. In addition, reflection can't be used in [Native AOT applications](../../../core/deploying/native-aot/index.md), so you must use source generation for those apps. +As an alternative, `System.Text.Json` can use the C# [source generation](../../../csharp/roslyn-sdk/source-generators-overview.md) feature to improve performance, reduce private memory usage, and facilitate [assembly trimming](../../../core/deploying/trimming/trim-self-contained.md), which reduces app size. In addition, certain reflection APIs can't be used in [Native AOT applications](../../../core/deploying/native-aot/index.md), so you must use source generation for those apps. Source generation can be used in two modes: * **Metadata collection mode** - During compilation, `System.Text.Json` collects the metadata needed for serialization and generates source code files. The generated source code files are automatically compiled as an integral part of the app. + During compilation, `System.Text.Json` collects the information needed for serialization and generates source code files that populate JSON contract metadata for the requested types. -* **Serialization optimization (fast track) mode** +* **Serialization optimization (fast path) mode** features that customize the output of serialization, such as naming policies and reference preservation, carry a performance overhead. In serialization optimization mode, System.Text.Json generates optimized code that uses [`Utf8JsonWriter`](use-utf8jsonwriter.md) directly. This optimized or *fast path* code increases serialization throughput. @@ -52,7 +52,7 @@ Choose reflection or source-generation modes based on the following benefits tha | Simpler to code and debug. | ✔️ | ❌ | ❌ | | Supports non-public accessors. | ✔️ | ❌ | ❌ | | Supports all available serialization customizations. | ✔️ | ❌ | ❌ | -| Reduces start-up time. | ❌ | ✔️ | ❌ | +| Reduces start-up time. | ❌ | ✔️ | ✔️ | | Reduces private memory usage. | ❌ | ✔️ | ✔️ | | Eliminates run-time reflection. | ❌ | ✔️ | ✔️ | | Facilitates trim-safe app size reduction. | ❌ | ✔️ | ✔️ | @@ -65,11 +65,10 @@ Choose reflection or source-generation modes based on the following benefits tha | Benefit | Reflection | Source generation:
Metadata collection | Source generation:
Serialization optimization | |------------------------------------------------------|------------|---------------------|----------------------------| | Simpler to code and debug. | ✔️ | ❌ | ❌ | -| Supports non-public accessors. | ✔️ | ❌ | ❌ | +| Supports non-public members. | ✔️ | ❌ | ❌ | | Supports required properties. | ✔️ | ❌ | ❌ | | Supports init-only properties. | ✔️ | ❌ | ❌ | -| Supports all available serialization customizations. | ✔️ | ❌ | ❌ | -| Reduces start-up time. | ❌ | ✔️ | ❌ | +| Reduces start-up time. | ❌ | ✔️ | ✔️ | | Reduces private memory usage. | ❌ | ✔️ | ✔️ | | Eliminates run-time reflection. | ❌ | ✔️ | ✔️ | | Facilitates trim-safe app size reduction. | ❌ | ✔️ | ✔️ | diff --git a/docs/standard/serialization/system-text-json/source-generation-modes.md b/docs/standard/serialization/system-text-json/source-generation-modes.md index f77e56712fb23..3c033899d4b46 100644 --- a/docs/standard/serialization/system-text-json/source-generation-modes.md +++ b/docs/standard/serialization/system-text-json/source-generation-modes.md @@ -49,9 +49,9 @@ The following table shows which options in `JsonSerializerOptions` are supported | Serialization option | Supported by optimized code | |------------------------------------------------------------------------|-----------------------------| -| | ❌ | +| | ✔️ | | | ❌ | -| | ❌ | +| | ✔️ | | | ✔️ | | | ❌ | | | ❌ | @@ -59,7 +59,7 @@ The following table shows which options in `JsonSerializerOptions` are supported | | ✔️ | | | ✔️ | | | ✔️ | -| | ❌ | +| | ✔️ | | | ❌ | | | ❌ | | | ✔️ | @@ -85,7 +85,7 @@ The following table shows which attributes are supported by the optimized serial | | ❌ | | | ✔️ | -If a non-supported option or attribute is specified for a type, the serializer falls back to the default `JsonSerializer` code. In that case, the optimized code isn't used when serializing that type but may be used for other types. Therefore it's important to do performance testing with your options and workloads to determine how much benefit you can actually get from serialization-optimization mode. Also, the ability to fall back to `JsonSerializer` code requires metadata-collection mode. If you select only serialization-optimization mode, serialization might fail for types or options that need to fall back to `JsonSerializer` code. +If a non-supported option or attribute is specified for a type, the serializer falls back to metadata mode, assuming that the source generator has been configured to generate metadata. In that case, the optimized code isn't used when serializing that type but may be used for other types. Therefore it's important to do performance testing with your options and workloads to determine how much benefit you can actually get from serialization-optimization mode. Also, the ability to fall back to `JsonSerializer` code requires metadata-collection mode. If you select only serialization-optimization mode, serialization might fail for types or options that need to fall back to `JsonSerializer` code. ## See also diff --git a/docs/standard/serialization/system-text-json/source-generation.md b/docs/standard/serialization/system-text-json/source-generation.md index 2ce6f63737da6..b26c2e6331aca 100644 --- a/docs/standard/serialization/system-text-json/source-generation.md +++ b/docs/standard/serialization/system-text-json/source-generation.md @@ -190,7 +190,7 @@ services.AddControllers().AddJsonOptions(options => ## Disable reflection defaults -Because System.Text.Json uses reflection by default, calling a basic serialization method can break Native AOT apps, which can't reflect at run time. These breaks can be challenging to diagnose since apps are often debugged using the CoreCLR runtime, where the code works. Instead, if you explicitly disable reflection-based serialization, breaks are easier to diagnose. Code that uses reflection-based serialization will cause an with a descriptive message to be thrown at run time. +Because System.Text.Json uses reflection by default, calling a basic serialization method can break Native AOT apps, which doesn't support all required reflection APIs. These breaks can be challenging to diagnose since they can be unpredictable, and apps are often debugged using the CoreCLR runtime, where reflection works. Instead, if you explicitly disable reflection-based serialization, breaks are easier to diagnose. Code that uses reflection-based serialization will cause an with a descriptive message to be thrown at run time. To disable default reflection in your app, set the `JsonSerializerIsReflectionEnabledByDefault` MSBuild property to `false` in your project file: From fc505448530132e16d8129a0eb448b17c77b4b22 Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Tue, 31 Oct 2023 12:06:54 -0700 Subject: [PATCH 7/7] respond to feedback --- .../system-text-json/overview.md | 2 +- .../reflection-vs-source-generation.md | 26 +++--- .../system-text-json/required-properties.md | 2 +- .../source-generation-modes.md | 87 +++++++++---------- .../system-text-json/source-generation.md | 30 ++++++- 5 files changed, 87 insertions(+), 60 deletions(-) diff --git a/docs/standard/serialization/system-text-json/overview.md b/docs/standard/serialization/system-text-json/overview.md index d56fb602e1d7c..d6b5910ad9fc5 100644 --- a/docs/standard/serialization/system-text-json/overview.md +++ b/docs/standard/serialization/system-text-json/overview.md @@ -25,7 +25,7 @@ For Visual Basic, there are some limitations on what parts of the library you ca ## How to get the library -The library is built-in as part of the shared framework for .NET Core 3.0 and later versions. The [source generation feature](source-generation-modes.md#metadata-collection-mode) is built-in as part of the shared framework for .NET 6 and later versions. Use of source generation requires .NET 5 SDK or later. +The library is built-in as part of the shared framework for .NET Core 3.0 and later versions. The [source generation feature](source-generation-modes.md#metadata-based-mode) is built-in as part of the shared framework for .NET 6 and later versions. For framework versions earlier than .NET Core 3.0, install the [System.Text.Json](https://www.nuget.org/packages/System.Text.Json) NuGet package. The package supports: diff --git a/docs/standard/serialization/system-text-json/reflection-vs-source-generation.md b/docs/standard/serialization/system-text-json/reflection-vs-source-generation.md index 2e35411acb1fc..4a38e9c3215c6 100644 --- a/docs/standard/serialization/system-text-json/reflection-vs-source-generation.md +++ b/docs/standard/serialization/system-text-json/reflection-vs-source-generation.md @@ -31,13 +31,15 @@ As an alternative, `System.Text.Json` can use the C# [source generation](../../. Source generation can be used in two modes: -* **Metadata collection mode** +* **Metadata-based mode** During compilation, `System.Text.Json` collects the metadata needed for serialization and generates source code files. The generated source code files are automatically compiled as an integral part of the app. -* **Serialization optimization (fast track) mode** +* **Serialization-optimization (fast path) mode** - features that customize the output of serialization, such as naming policies and reference preservation, carry a performance overhead. In serialization optimization mode, System.Text.Json generates optimized code that uses [`Utf8JsonWriter`](use-utf8jsonwriter.md) directly. This optimized or *fast path* code increases serialization throughput. + features that customize the output of serialization, such as naming policies and reference preservation, carry a performance overhead. In serialization-optimization mode, System.Text.Json generates optimized serialization code that uses [`Utf8JsonWriter`](use-utf8jsonwriter.md) directly. This optimized or *fast path* code increases serialization throughput. + + Fast-path *deserialization* isn't currently available. For more information, see [dotnet/runtime issue 55043](https://github.com/dotnet/runtime/issues/55043). Source generation for `System.Text.Json` requires C# 9.0 or a later version. @@ -47,25 +49,29 @@ Choose reflection or source-generation modes based on the following benefits tha :::zone pivot="dotnet-8-0" -| Benefit | Reflection | Source generation
(Metadata collection mode) | Source generation
(Serialization optimization mode) | +| Benefit | Reflection | Source generation
(Metadata-based mode) | Source generation
(Serialization-optimization mode) | |------------------------------------------------------|------------|---------------------|----------------------------| -| Simpler to code and debug. | ✔️ | ❌ | ❌ | -| Supports non-public accessors. | ✔️ | ❌ | ❌ | -| Supports all available serialization customizations. | ✔️ | ❌ | ❌ | +| Simpler to code. | ✔️ | ❌ | ❌ | +| Simpler to debug. | ❌ | ✔️ | ✔️ | +| Supports non-public members. | ✔️ | ✔️* | ✔️* | +| Supports all available serialization customizations. | ✔️ | ❌ | ❌ | | Reduces start-up time. | ❌ | ✔️ | ❌ | | Reduces private memory usage. | ❌ | ✔️ | ✔️ | | Eliminates run-time reflection. | ❌ | ✔️ | ✔️ | | Facilitates trim-safe app size reduction. | ❌ | ✔️ | ✔️ | | Increases serialization throughput. | ❌ | ❌ | ✔️ | +\* The source generator supports *some* non-public members, for example, internal types in the same assembly. +† Source-generated contracts can be modified using the contract customization API. + :::zone-end :::zone pivot="dotnet-7-0,dotnet-6-0" -| Benefit | Reflection | Source generation:
Metadata collection | Source generation:
Serialization optimization | +| Benefit | Reflection | Source generation
(Metadata-based mode) | Source generation
(Serialization-optimization mode) | |------------------------------------------------------|------------|---------------------|----------------------------| -| Simpler to code and debug. | ✔️ | ❌ | ❌ | -| Supports non-public accessors. | ✔️ | ❌ | ❌ | +| Simpler to code. | ✔️ | ❌ | ❌ | +| Simpler to debug. | ❌ | ❌ | ✔️ | | Supports required properties. | ✔️ | ❌ | ❌ | | Supports init-only properties. | ✔️ | ❌ | ❌ | | Supports all available serialization customizations. | ✔️ | ❌ | ❌ | diff --git a/docs/standard/serialization/system-text-json/required-properties.md b/docs/standard/serialization/system-text-json/required-properties.md index 47b26827b46bf..3bca34f4c3c89 100644 --- a/docs/standard/serialization/system-text-json/required-properties.md +++ b/docs/standard/serialization/system-text-json/required-properties.md @@ -18,7 +18,7 @@ From the serializer's perspective, these two demarcations are equivalent and bot - If you're using a programming language other than C# or a down-level version of C#. - If you only want the requirement to apply to JSON deserialization. -- If you're using `System.Text.Json` serialization in [source generation](source-generation-modes.md#metadata-collection-mode) mode. In this case, your code won't compile if you use the `required` modifier, as source generation occurs at compile time. +- If you're using `System.Text.Json` serialization in [source generation](source-generation-modes.md#metadata-based-mode) mode. In this case, your code won't compile if you use the `required` modifier, as source generation occurs at compile time. The following code snippet shows an example of a property modified with the `required` keyword. This property must be present in the JSON payload for deserialization to succeed. diff --git a/docs/standard/serialization/system-text-json/source-generation-modes.md b/docs/standard/serialization/system-text-json/source-generation-modes.md index f77e56712fb23..e84f973b868a6 100644 --- a/docs/standard/serialization/system-text-json/source-generation-modes.md +++ b/docs/standard/serialization/system-text-json/source-generation-modes.md @@ -13,11 +13,11 @@ helpviewer_keywords: # Source-generation modes in System.Text.Json -Source generation can be used in two modes: metadata collection and serialization optimization. This article describes the different modes. +Source generation can be used in two modes: metadata-based and serialization optimization. This article describes the different modes. For information about how to use source generation modes, see [How to use source generation in System.Text.Json](source-generation.md). -## Metadata collection mode +## Metadata-based mode You can use source generation to move the metadata collection process from run time to compile time. During compilation, the metadata is collected and source code files are generated. The generated source code files are automatically compiled as an integral part of the application. This technique eliminates run-time metadata collection, which improves performance of both serialization and deserialization. @@ -39,53 +39,52 @@ Only `public` properties and fields are supported by default in either serializa For information about other known issues with source generation, see the [GitHub issues that are labeled "source-generator"](https://github.com/dotnet/runtime/issues?q=is%3Aopen+is%3Aissue+label%3Aarea-System.Text.Json+label%3Asource-generator) in the *dotnet/runtime* repository. -## Serialization optimization mode +## Serialization-optimization (fast path) mode `JsonSerializer` has many features that customize the output of serialization, such as [naming policies](customize-properties.md#use-a-built-in-naming-policy) and [preserving references](preserve-references.md#preserve-references-and-handle-circular-references). Support for all those features causes some performance overhead. Source generation can improve serialization performance by generating optimized code that uses [`Utf8JsonWriter`](use-utf8jsonwriter.md) directly. The optimized code doesn't support all of the serialization features that `JsonSerializer` supports. The serializer detects whether the optimized code can be used and falls back to default serialization code if unsupported options are specified. For example, isn't applicable to writing, so specifying this option doesn't cause a fallback to default code. -The following table shows which options in `JsonSerializerOptions` are supported by the optimized serialization code: - -| Serialization option | Supported by optimized code | -|------------------------------------------------------------------------|-----------------------------| -| | ❌ | -| | ❌ | -| | ❌ | -| | ✔️ | -| | ❌ | -| | ❌ | -| | ❌ | -| | ✔️ | -| | ✔️ | -| | ✔️ | -| | ❌ | -| | ❌ | -| | ❌ | -| | ✔️ | -| | ❌ | -| | ❌ | -| | ✔️ | -| | ❌ | -| | ✔️ | - -The following table shows which attributes are supported by the optimized serialization code: - -| Attribute | Supported by optimized code | -|-------------------------------------------------------------------|-----------------------------| -| | ❌ | -| | ❌ | -| | ✔️ | -| | ❌ | -| | ✔️ | -| | ✔️ | -| | ❌ | -| | ✔️ | -| | ✔️ | -| | ❌ | -| | ✔️ | - -If a non-supported option or attribute is specified for a type, the serializer falls back to the default `JsonSerializer` code. In that case, the optimized code isn't used when serializing that type but may be used for other types. Therefore it's important to do performance testing with your options and workloads to determine how much benefit you can actually get from serialization-optimization mode. Also, the ability to fall back to `JsonSerializer` code requires metadata-collection mode. If you select only serialization-optimization mode, serialization might fail for types or options that need to fall back to `JsonSerializer` code. +The following table shows which options in `JsonSerializerOptions` are supported by fast-path serialization: + +| Serialization option | Supported for fast-path | +|------------------------------------------------------------------------|-------------------------| +| | ❌ | +| | ❌ | +| | ❌ | +| | ✔️ | +| | ❌ | +| | ❌ | +| | ❌ | +| | ✔️ | +| | ✔️ | +| | ✔️ | +| | ❌ | +| | ❌ | +| | ✔️ | +| | ❌ | +| | ✔️ | +| | ✔️ | + +(The following options aren't supported because they apply only to *de*serialization: , , and .) + +The following table shows which attributes are supported by fast-path serialization: + +| Attribute | Supported for fast-path | +|-------------------------------------------------------------------|-------------------------| +| | ❌ | +| | ❌ | +| | ✔️ | +| | ❌ | +| | ✔️ | +| | ✔️ | +| | ❌ | +| | ✔️ | +| | ✔️ | +| | ❌ | +| | ✔️ | + +If a non-supported option or attribute is specified for a type, the serializer falls back to the default `JsonSerializer` code. In that case, the optimized code isn't used when serializing that type but may be used for other types. Therefore it's important to do performance testing with your options and workloads to determine how much benefit you can actually get from serialization-optimization mode. Also, the ability to fall back to `JsonSerializer` code requires metadata-based mode. If you select only serialization-optimization mode, serialization might fail for types or options that need to fall back to `JsonSerializer` code. ## See also diff --git a/docs/standard/serialization/system-text-json/source-generation.md b/docs/standard/serialization/system-text-json/source-generation.md index 2ce6f63737da6..f251f53715419 100644 --- a/docs/standard/serialization/system-text-json/source-generation.md +++ b/docs/standard/serialization/system-text-json/source-generation.md @@ -97,12 +97,12 @@ Here are the preceding examples in a complete program: ## Specify source-generation mode -You can specify metadata-collection mode or serialization-optimization mode for an entire context, which may include multiple types. Or you can specify the mode for an individual type. If you do both, the mode specification for a type wins. +You can specify metadata-based mode or serialization-optimization mode for an entire context, which may include multiple types. Or you can specify the mode for an individual type. If you do both, the mode specification for a type wins. - For an entire context, use the property. - For an individual type, use the property. -### Serialization-optimization mode example +### Serialization-optimization (fast path) mode example - For an entire context: @@ -116,7 +116,7 @@ You can specify metadata-collection mode or serialization-optimization mode for :::code language="csharp" source="snippets/source-generation/csharp/SerializeOnlyNoOptions.cs" id="All"::: -### Metadata-collection mode example +### Metadata-based mode example - For an entire context: @@ -148,7 +148,29 @@ Starting with .NET 8, you can also use overloads of property to specify the context. + +```csharp +[JsonSerializable(typeof(WeatherForecast[]))] +internal partial class MyJsonContext : JsonSerializerContext { } +``` + +```csharp +var serializerOptions = new JsonSerializerOptions +{ + TypeInfoResolver = MyJsonContext.Default; +}; + +services.AddControllers().AddJsonOptions( + static options => + options.TypeInfoResolverChain.Add(MyJsonContext.Default)); +``` + +:::zone-end + +:::zone pivot="dotnet-7-0" In Razor Pages, MVC, SignalR, and Web API apps, use the property to specify the context.