Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 110 additions & 48 deletions docs/core/whats-new/dotnet-11/libraries.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/core/whats-new/dotnet-11/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: What's new in .NET 11
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.
titleSuffix: ""
ms.date: 08/12/2026
ms.date: 08/18/2026
ai-usage: ai-assisted
ms.update-cycle: 3650-days
---
Expand Down Expand Up @@ -36,7 +36,7 @@ The .NET 11 libraries include new APIs for:
- <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.
- 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.
- 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>.
- 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.
- 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.
- Built-in OpenTelemetry metrics for <xref:Microsoft.Extensions.Caching.Memory.MemoryCache>.
- Discriminated-union scaffolding (`UnionAttribute` and `IUnion`) in <xref:System.Runtime.CompilerServices>.
- Tar archive format selection and GNU sparse format 1.0 support.
Expand Down
45 changes: 28 additions & 17 deletions docs/core/whats-new/dotnet-11/snippets/csharp/Libraries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ static void Utf8JsonWriterResetExample()
writer.WriteEndObject();
writer.Flush();

// Reset with different options for next use — no new allocation needed
// Reuse the writer with different output options.
stream.SetLength(0);
writer.Reset(stream, new JsonWriterOptions { Indented = false });
// </Utf8JsonWriterReset>
Expand All @@ -86,19 +86,20 @@ static void Utf8JsonWriterResetExample()
static void JsonTypeInfoExample()
{
// <JsonTypeInfoGeneric>
JsonSerializerOptions options = new(JsonSerializerDefaults.Web);
options.MakeReadOnly();
JsonSerializerOptions options = new()
{
TypeInfoResolver = new DefaultJsonTypeInfoResolver()
};

// Before: manual downcast required
// Previously, a manual downcast was required.
JsonTypeInfo<MyRecord> info1 = (JsonTypeInfo<MyRecord>)options.GetTypeInfo(typeof(MyRecord));

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

// TryGetTypeInfo variant for cases where the type may not be registered
// TryGetTypeInfo reports whether the configured resolver handles the type.
if (options.TryGetTypeInfo<MyRecord>(out JsonTypeInfo<MyRecord>? typeInfo))
{
// Use typeInfo
_ = typeInfo;
}
// </JsonTypeInfoGeneric>
Expand All @@ -107,18 +108,18 @@ static void JsonTypeInfoExample()
static void JsonNamingIgnoreExample()
{
// <JsonNamingIgnore>
// Type-level JsonIgnore: all members use WhenWritingNull by default
// Per-member JsonNamingPolicy: EventName uses camelCase even though the
// serializer options use PascalCase
// Type-level JsonIgnore omits null members by default. The type-level
// naming policy overrides the global policy, and the member policy wins
// for EventName.
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.PascalCase
};

var data = new EventData { EventName = "Launch", Notes = null };
var data = new EventData { EventName = "Launch", ReleaseVersion = "11", Notes = null };
string json = JsonSerializer.Serialize(data, options);
Console.WriteLine(json);
// {"eventName":"Launch"} -- Notes omitted (null), EventName camel-cased
// {"eventName":"Launch","release_version":"11"}
// </JsonNamingIgnore>
}

Expand Down Expand Up @@ -281,18 +282,25 @@ static async IAsyncEnumerable<int> GenerateNumbers()
}
}

var pipe = new Pipe();
using var arrayStream = new MemoryStream();
PipeWriter arrayPipe = PipeWriter.Create(arrayStream);

// Write a JSON array: [0,1,2,3,4]
// Write a JavaScript Object Notation (JSON) array: [0,1,2,3,4]
await JsonSerializer.SerializeAsyncEnumerable(
pipe.Writer,
arrayPipe,
GenerateNumbers());
await arrayPipe.CompleteAsync();

// Write NDJSON (one value per line): 0\n1\n2\n3\n4\n
using var jsonlStream = new MemoryStream();
PipeWriter jsonlPipe = PipeWriter.Create(jsonlStream);

// Write canonical JSON Lines (JSONL). Each value is followed by \n.
// Output: 0\n1\n2\n3\n4\n
await JsonSerializer.SerializeAsyncEnumerable(
pipe.Writer,
jsonlPipe,
GenerateNumbers(),
topLevelValues: true);
await jsonlPipe.CompleteAsync();
// </JsonSerializeAsyncEnumerablePipe>
}

Expand Down Expand Up @@ -327,11 +335,14 @@ static void NullableUnderlyingTypeExample()

record MyRecord(string Name, int Value);

[JsonNamingPolicy(JsonKnownNamingPolicy.SnakeCaseLower)]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
sealed class EventData
{
[JsonNamingPolicy(JsonKnownNamingPolicy.CamelCase)]
public string EventName { get; set; } = "";

public string ReleaseVersion { get; set; } = "";

public string? Notes { get; set; }
}
2 changes: 2 additions & 0 deletions docs/fundamentals/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,8 @@ items:
href: ../standard/serialization/system-text-json/preserve-references.md
- name: Serialize polymorphic types
href: ../standard/serialization/system-text-json/polymorphism.md
- name: Serialize union types
href: ../standard/serialization/system-text-json/union-types.md
- name: Use extension methods on HttpClient
href: ../standard/serialization/system-text-json/httpclient-extensions.md
- name: Read/write JSON without using JsonSerializer
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "How to write custom converters for JSON serialization - .NET"
description: "Learn how to create custom converters for the JSON serialization classes that are provided in the System.Text.Json namespace."
ms.date: 03/23/2026
ms.date: 08/18/2026
no-loc: [System.Text.Json, Newtonsoft.Json]
helpviewer_keywords:
- "JSON serialization"
Expand Down Expand Up @@ -89,11 +89,11 @@ The `Enum` type is similar to an open generic type: a converter for `Enum` has t

## Use open generic converters with [JsonConverter]

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.
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.

### Define the generic type

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

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

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

> [!NOTE]
> If the type parameter count on the converter doesn't match the target type, an <xref:System.InvalidOperationException> is thrown at runtime.
> 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.

## The use of `Utf8JsonReader` in the `Read` method

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
---
title: Custom serialization and deserialization contracts
description: "Learn how to write your own contract resolution logic to customize the JSON contract for a type."
ms.date: 06/15/2023
ms.date: 08/18/2026
ai-usage: ai-assisted
---
# Customize a JSON contract

Expand Down Expand Up @@ -45,15 +46,30 @@ There are two ways to plug into customization. Both involve obtaining a resolver
- If a type isn't handled, <xref:System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver.GetTypeInfo*?displayProperty=nameWithType> should return `null` for that type.
- 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.

## Get strongly typed metadata

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)>:

```csharp
JsonTypeInfo<WeatherForecast> typeInfo =
options.GetTypeInfo<WeatherForecast>();

bool found = options.TryGetTypeInfo<WeatherForecast>(
out JsonTypeInfo<WeatherForecast>? optionalTypeInfo);
```

`TryGetTypeInfo<T>` returns `false` when no resolver supplies metadata for `T`.

## Configurable aspects

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:
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:

| `JsonTypeInfo.Kind` | Description |
|---------------------|-------------|
| <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.** |
| <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. |
| <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>`. |
| <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. |
| <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. |

## Modifiers
Expand All @@ -68,6 +84,7 @@ The following table shows the modifications you can make and how to achieve them
| 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) |
| 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) |
| 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) |
| 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) |

## Example: Increment a property's value

Expand Down
Loading
Loading