Source-generation modes in System.Text.Json
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.
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.
The performance improvements provided by source generation can be substantial. For example, test results have shown up to 40% or more startup time reduction, private memory reduction, throughput speed increase (in serialization optimization mode), and app size reduction.
Known issues
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 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
members and private
accessors, while source-generation mode doesn't. For example, if you apply the JsonInclude attribute 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.
For information about other known issues with source generation, see the GitHub issues that are labeled "source-generator" in the dotnet/runtime repository.
Serialization-optimization (fast path) mode
JsonSerializer
has many features that customize the output of serialization, such as naming policies and preserving references. Support for all those features causes some performance overhead. Source generation can improve serialization performance by generating optimized code that uses Utf8JsonWriter
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, JsonNumberHandling.AllowReadingFromString 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 fast-path serialization:
Serialization option | Supported for fast-path |
---|---|
AllowTrailingCommas | ✔️ |
Converters | ❌ |
DefaultBufferSize | ✔️ |
DefaultIgnoreCondition | ✔️ |
DictionaryKeyPolicy | ❌ |
Encoder | ❌ |
IgnoreNullValues | ❌ |
IgnoreReadOnlyFields | ✔️ |
IgnoreReadOnlyProperties | ✔️ |
IncludeFields | ✔️ |
MaxDepth | ✔️ |
NumberHandling | ❌ |
PropertyNamingPolicy | ✔️ |
ReferenceHandler | ❌ |
TypeInfoResolver | ✔️ |
WriteIndented | ✔️ |
(The following options aren't supported because they apply only to deserialization: PropertyNameCaseInsensitive, ReadCommentHandling, and UnknownTypeHandling.)
The following table shows which attributes are supported by fast-path serialization:
Attribute | Supported for fast-path |
---|---|
JsonConstructorAttribute | ❌ |
JsonConverterAttribute | ❌ |
JsonDerivedTypeAttribute | ✔️ |
JsonExtensionDataAttribute | ❌ |
JsonIgnoreAttribute | ✔️ |
JsonIncludeAttribute | ✔️ |
JsonNumberHandlingAttribute | ❌ |
JsonPolymorphicAttribute | ✔️ |
JsonPropertyNameAttribute | ✔️ |
JsonPropertyOrderAttribute | ✔️ |
JsonRequiredAttribute | ✔️ |
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.