Skip to content

Commit 7caa9d1

Browse files
Document System.Text.Json updates for .NET 11
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0d38be7f-79b2-4e2a-9eb4-f7266c6ca5ac
1 parent 499635f commit 7caa9d1

17 files changed

Lines changed: 634 additions & 148 deletions

docs/core/whats-new/dotnet-11/libraries.md

Lines changed: 110 additions & 48 deletions
Large diffs are not rendered by default.

docs/core/whats-new/dotnet-11/overview.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: What's new in .NET 11
33
description: Learn about the new features introduced in .NET 11 for the runtime, libraries, and SDK. Also find links to what's new in other areas, such as ASP.NET Core.
44
titleSuffix: ""
5-
ms.date: 08/12/2026
5+
ms.date: 08/18/2026
66
ai-usage: ai-assisted
77
ms.update-cycle: 3650-days
88
---
@@ -36,7 +36,7 @@ The .NET 11 libraries include new APIs for:
3636
- <xref:System.Diagnostics.Process> expansion with run-and-capture helpers, fire-and-forget launches, <xref:Microsoft.Win32.SafeHandles.SafeProcessHandle> lifecycle methods, tighter handle control, and new <xref:System.Diagnostics.ProcessStartInfo.StartSuspended?displayProperty=nameWithType> for suspended starts and <xref:System.Diagnostics.Process.TryGetProcessById(System.Int32,System.Diagnostics.Process@)?displayProperty=nameWithType> for safe process lookup.
3737
- Compression, including improved Base64 APIs, new methods for ZIP archive entries, Zstandard compression in <xref:System.IO.Compression?displayProperty=fullName>, and CRC32 validation when reading ZIP entries.
3838
- New numeric APIs, including IEEE 754 decimal floating-point types (<xref:System.Numerics.Decimal32>, <xref:System.Numerics.Decimal64>, and <xref:System.Numerics.Decimal128>), <xref:System.Numerics.INumberBase`1.TryParsePartial*?displayProperty=nameWithType> for delimiter-aware parsing, and generic <xref:System.Numerics.Complex`1>.
39-
- System.Text.Json improvements, including generic type info retrieval, <xref:System.Text.Json.JsonNamingPolicy.PascalCase?displayProperty=nameWithType>, per-member naming policy overrides, type-level ignore conditions, F# discriminated union support, <xref:System.Text.Json.Utf8JsonWriter.Reset*?displayProperty=nameWithType> with options, `SerializeAsyncEnumerable` overloads for `PipeWriter` targets and top-level values (NDJSON) output, and serialization of C# union types.
39+
- System.Text.Json improvements, including C# and F# union support, JSON Lines (JSONL) output, expanded polymorphism and source generation, new naming and ignore controls, and built-in numeric converters and collection contracts.
4040
- Built-in OpenTelemetry metrics for <xref:Microsoft.Extensions.Caching.Memory.MemoryCache>.
4141
- Discriminated-union scaffolding (`UnionAttribute` and `IUnion`) in <xref:System.Runtime.CompilerServices>.
4242
- Tar archive format selection and GNU sparse format 1.0 support.

docs/core/whats-new/dotnet-11/snippets/csharp/Libraries.cs

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ static void Utf8JsonWriterResetExample()
7777
writer.WriteEndObject();
7878
writer.Flush();
7979

80-
// Reset with different options for next use — no new allocation needed
80+
// Reuse the writer with different output options.
8181
stream.SetLength(0);
8282
writer.Reset(stream, new JsonWriterOptions { Indented = false });
8383
// </Utf8JsonWriterReset>
@@ -86,19 +86,20 @@ static void Utf8JsonWriterResetExample()
8686
static void JsonTypeInfoExample()
8787
{
8888
// <JsonTypeInfoGeneric>
89-
JsonSerializerOptions options = new(JsonSerializerDefaults.Web);
90-
options.MakeReadOnly();
89+
JsonSerializerOptions options = new()
90+
{
91+
TypeInfoResolver = new DefaultJsonTypeInfoResolver()
92+
};
9193

92-
// Before: manual downcast required
94+
// Previously, a manual downcast was required.
9395
JsonTypeInfo<MyRecord> info1 = (JsonTypeInfo<MyRecord>)options.GetTypeInfo(typeof(MyRecord));
9496

95-
// After: generic method returns the right type directly
97+
// The generic method returns the correct type directly.
9698
JsonTypeInfo<MyRecord> info2 = options.GetTypeInfo<MyRecord>();
9799

98-
// TryGetTypeInfo variant for cases where the type may not be registered
100+
// TryGetTypeInfo reports whether the configured resolver handles the type.
99101
if (options.TryGetTypeInfo<MyRecord>(out JsonTypeInfo<MyRecord>? typeInfo))
100102
{
101-
// Use typeInfo
102103
_ = typeInfo;
103104
}
104105
// </JsonTypeInfoGeneric>
@@ -107,18 +108,18 @@ static void JsonTypeInfoExample()
107108
static void JsonNamingIgnoreExample()
108109
{
109110
// <JsonNamingIgnore>
110-
// Type-level JsonIgnore: all members use WhenWritingNull by default
111-
// Per-member JsonNamingPolicy: EventName uses camelCase even though the
112-
// serializer options use PascalCase
111+
// Type-level JsonIgnore omits null members by default. The type-level
112+
// naming policy overrides the global policy, and the member policy wins
113+
// for EventName.
113114
var options = new JsonSerializerOptions
114115
{
115116
PropertyNamingPolicy = JsonNamingPolicy.PascalCase
116117
};
117118

118-
var data = new EventData { EventName = "Launch", Notes = null };
119+
var data = new EventData { EventName = "Launch", ReleaseVersion = "11", Notes = null };
119120
string json = JsonSerializer.Serialize(data, options);
120121
Console.WriteLine(json);
121-
// {"eventName":"Launch"} -- Notes omitted (null), EventName camel-cased
122+
// {"eventName":"Launch","release_version":"11"}
122123
// </JsonNamingIgnore>
123124
}
124125

@@ -281,18 +282,25 @@ static async IAsyncEnumerable<int> GenerateNumbers()
281282
}
282283
}
283284

284-
var pipe = new Pipe();
285+
using var arrayStream = new MemoryStream();
286+
PipeWriter arrayPipe = PipeWriter.Create(arrayStream);
285287

286-
// Write a JSON array: [0,1,2,3,4]
288+
// Write a JavaScript Object Notation (JSON) array: [0,1,2,3,4]
287289
await JsonSerializer.SerializeAsyncEnumerable(
288-
pipe.Writer,
290+
arrayPipe,
289291
GenerateNumbers());
292+
await arrayPipe.CompleteAsync();
290293

291-
// Write NDJSON (one value per line): 0\n1\n2\n3\n4\n
294+
using var jsonlStream = new MemoryStream();
295+
PipeWriter jsonlPipe = PipeWriter.Create(jsonlStream);
296+
297+
// Write canonical JSON Lines (JSONL). Each value is followed by \n.
298+
// Output: 0\n1\n2\n3\n4\n
292299
await JsonSerializer.SerializeAsyncEnumerable(
293-
pipe.Writer,
300+
jsonlPipe,
294301
GenerateNumbers(),
295302
topLevelValues: true);
303+
await jsonlPipe.CompleteAsync();
296304
// </JsonSerializeAsyncEnumerablePipe>
297305
}
298306

@@ -327,11 +335,14 @@ static void NullableUnderlyingTypeExample()
327335

328336
record MyRecord(string Name, int Value);
329337

338+
[JsonNamingPolicy(JsonKnownNamingPolicy.SnakeCaseLower)]
330339
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
331340
sealed class EventData
332341
{
333342
[JsonNamingPolicy(JsonKnownNamingPolicy.CamelCase)]
334343
public string EventName { get; set; } = "";
335344

345+
public string ReleaseVersion { get; set; } = "";
346+
336347
public string? Notes { get; set; }
337348
}

docs/fundamentals/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,8 @@ items:
609609
href: ../standard/serialization/system-text-json/preserve-references.md
610610
- name: Serialize polymorphic types
611611
href: ../standard/serialization/system-text-json/polymorphism.md
612+
- name: Serialize union types
613+
href: ../standard/serialization/system-text-json/union-types.md
612614
- name: Use extension methods on HttpClient
613615
href: ../standard/serialization/system-text-json/httpclient-extensions.md
614616
- name: Read/write JSON without using JsonSerializer

docs/standard/serialization/system-text-json/converters-how-to.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: "How to write custom converters for JSON serialization - .NET"
33
description: "Learn how to create custom converters for the JSON serialization classes that are provided in the System.Text.Json namespace."
4-
ms.date: 03/23/2026
4+
ms.date: 08/18/2026
55
no-loc: [System.Text.Json, Newtonsoft.Json]
66
helpviewer_keywords:
77
- "JSON serialization"
@@ -89,11 +89,11 @@ The `Enum` type is similar to an open generic type: a converter for `Enum` has t
8989

9090
## Use open generic converters with [JsonConverter]
9191

92-
Starting in .NET 11, <xref:System.Text.Json.Serialization.JsonConverterAttribute> supports open generic converter types on generic types when the total type parameter arity matches. This feature lets you apply a `[JsonConverter]` attribute directly using an open generic converter type (for example, `typeof(OptionConverter<>)`) without implementing a <xref:System.Text.Json.Serialization.JsonConverterFactory>. The serializer automatically constructs the closed generic converter at runtime.
92+
Starting in .NET 11, <xref:System.Text.Json.Serialization.JsonConverterAttribute> supports open generic converter types on generic types when the total type parameter arity matches. This feature lets you apply a `[JsonConverter]` attribute directly using an open generic converter type (for example, `typeof(OptionConverter<>)`) without implementing a <xref:System.Text.Json.Serialization.JsonConverterFactory>. The serializer automatically constructs the closed generic converter. Reflection-based serialization and source generation both support this feature.
9393

9494
### Define the generic type
9595

96-
Annotate your generic type with `[JsonConverter]`, specifying the open generic converter type. The type parameter count on the converter must match the target type:
96+
Annotate your generic type with `[JsonConverter]`, specifying the open generic converter type. The converter and target type must have matching total generic arity:
9797

9898
:::code language="csharp" source="snippets/converters-how-to/csharp/OpenGenericConverter.cs" id="OptionType":::
9999

@@ -149,7 +149,7 @@ Continue to use <xref:System.Text.Json.Serialization.JsonConverterFactory> when:
149149
* You register the converter through <xref:System.Text.Json.JsonSerializerOptions.Converters?displayProperty=nameWithType> instead of the `[JsonConverter]` attribute.
150150

151151
> [!NOTE]
152-
> If the type parameter count on the converter doesn't match the target type, an <xref:System.InvalidOperationException> is thrown at runtime.
152+
> At run time, using an open generic converter on a non-generic type or with mismatched total generic arity throws an <xref:System.InvalidOperationException>. The message identifies the converter and target type.
153153
154154
## The use of `Utf8JsonReader` in the `Read` method
155155

docs/standard/serialization/system-text-json/custom-contracts.md

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
---
22
title: Custom serialization and deserialization contracts
33
description: "Learn how to write your own contract resolution logic to customize the JSON contract for a type."
4-
ms.date: 06/15/2023
4+
ms.date: 08/18/2026
5+
ai-usage: ai-assisted
56
---
67
# Customize a JSON contract
78

@@ -45,15 +46,30 @@ There are two ways to plug into customization. Both involve obtaining a resolver
4546
- If a type isn't handled, <xref:System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver.GetTypeInfo*?displayProperty=nameWithType> should return `null` for that type.
4647
- You can also combine your custom resolver with others, for example, the default resolver. The resolvers will be queried in order until a non-null <xref:System.Text.Json.Serialization.Metadata.JsonTypeInfo> value is returned for the type.
4748

49+
## Get strongly typed metadata
50+
51+
Starting in .NET 11, use <xref:System.Text.Json.JsonSerializerOptions.GetTypeInfo``1?displayProperty=nameWithType> and <xref:System.Text.Json.JsonSerializerOptions.TryGetTypeInfo``1(System.Text.Json.Serialization.Metadata.JsonTypeInfo{``0}@)?displayProperty=nameWithType> as strongly typed alternatives to casting the result of <xref:System.Text.Json.JsonSerializerOptions.GetTypeInfo(System.Type)>:
52+
53+
```csharp
54+
JsonTypeInfo<WeatherForecast> typeInfo =
55+
options.GetTypeInfo<WeatherForecast>();
56+
57+
bool found = options.TryGetTypeInfo<WeatherForecast>(
58+
out JsonTypeInfo<WeatherForecast>? optionalTypeInfo);
59+
```
60+
61+
`TryGetTypeInfo<T>` returns `false` when no resolver supplies metadata for `T`.
62+
4863
## Configurable aspects
4964

50-
The <xref:System.Text.Json.Serialization.Metadata.JsonTypeInfo.Kind?displayProperty=nameWithType> property indicates how the converter serializes a given type&mdash;for example, as an object or as an array, and whether its properties are serialized. You can query this property to determine which aspects of a type's JSON contract you can configure. There are four different kinds:
65+
The <xref:System.Text.Json.Serialization.Metadata.JsonTypeInfo.Kind?displayProperty=nameWithType> property indicates how the converter serializes a given type&mdash;for example, as an object or as an array, and whether its properties are serialized. Query this property to determine which aspects of a type's JSON contract you can configure. The property has five possible values:
5166

5267
| `JsonTypeInfo.Kind` | Description |
5368
|---------------------|-------------|
5469
| <xref:System.Text.Json.Serialization.Metadata.JsonTypeInfoKind.Object?displayProperty=nameWithType> | The converter will serialize the type into a JSON object and uses its properties. **This kind is used for most class and struct types and allows for the most flexibility.** |
5570
| <xref:System.Text.Json.Serialization.Metadata.JsonTypeInfoKind.Enumerable?displayProperty=nameWithType> | The converter will serialize the type into a JSON array. This kind is used for types like `List<T>` and array. |
5671
| <xref:System.Text.Json.Serialization.Metadata.JsonTypeInfoKind.Dictionary?displayProperty=nameWithType> | The converter will serialize the type into a JSON object. This kind is used for types like `Dictionary<K, V>`. |
72+
| <xref:System.Text.Json.Serialization.Metadata.JsonTypeInfoKind.Union?displayProperty=nameWithType> | The converter serializes the active case value from a union. Starting in .NET 11, this kind is used for C# union types and exposes case, classifier, constructor, and deconstructor metadata. |
5773
| <xref:System.Text.Json.Serialization.Metadata.JsonTypeInfoKind.None?displayProperty=nameWithType> | The converter doesn't specify how it will serialize the type or what `JsonTypeInfo` properties it will use. This kind is used for types like <xref:System.Object?displayProperty=nameWithType>, `int`, and `string`, and for all types that use a custom converter. |
5874

5975
## Modifiers
@@ -68,6 +84,7 @@ The following table shows the modifications you can make and how to achieve them
6884
| Add or remove properties | `JsonTypeInfoKind.Object` | Add or remove items from the <xref:System.Text.Json.Serialization.Metadata.JsonTypeInfo.Properties?displayProperty=nameWithType> list. | [Serialize private fields](#example-serialize-private-fields) |
6985
| Conditionally serialize a property | `JsonTypeInfoKind.Object` | Modify the <xref:System.Text.Json.Serialization.Metadata.JsonPropertyInfo.ShouldSerialize?displayProperty=nameWithType> predicate for the property. | [Ignore properties with a specific type](#example-ignore-properties-with-a-specific-type) |
7086
| Customize number handling for a specific type | `JsonTypeInfoKind.None` | Modify the <xref:System.Text.Json.Serialization.Metadata.JsonTypeInfo.NumberHandling?displayProperty=nameWithType> value for the type. | [Allow int values to be strings](#example-allow-int-values-to-be-strings) |
87+
| Customize union cases or classification | `JsonTypeInfoKind.Union` | Modify the union cases, classifier, constructor, or deconstructor on <xref:System.Text.Json.Serialization.Metadata.JsonTypeInfo>. | [Serialize union types](union-types.md#customize-a-union-contract) |
7188

7289
## Example: Increment a property's value
7390

0 commit comments

Comments
 (0)