Skip to content

Commit cf60c63

Browse files
authored
Docs - Json+PipeReader deserialization support in MVC and Minimal APIs (#36102)
1 parent c80b69d commit cf60c63

File tree

4 files changed

+69
-3
lines changed

4 files changed

+69
-3
lines changed

aspnetcore/fundamentals/minimal-apis.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ The <xref:System.Delegate> arguments passed to these methods are called "route h
7070

7171
[!INCLUDE [](~/fundamentals/minimal-apis/includes/parameter-binding10.md)]
7272

73+
## Json+PipeReader deserialization in minimal APIs
74+
75+
[!INCLUDE [](~/includes/net10pipereader.md)]
76+
7377
## Validation support in Minimal APIs
7478

7579
Enabling validation allows the ASP.NET Core runtime to perform validations defined on the:

aspnetcore/fundamentals/minimal-apis/includes/parameter-binding10.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,4 +427,4 @@ The preceding code:
427427
* Accesses the request body using <xref:Microsoft.AspNetCore.Http.HttpRequest.BodyReader?displayProperty=nameWithType>.
428428
* Copies the request body to a local file.
429429

430-
:::moniker-end
430+
:::moniker-end
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<!--
2+
This include file is used in
3+
minimal-apis.md
4+
model-binding.md
5+
-->
6+
7+
Starting in .NET 10, the following functional areas of ASP.NET Core use overloads of <xref:System.Text.Json.JsonSerializer.DeserializeAsync%2A?displayProperty=nameWithType> based on PipeReader instead of Stream:
8+
9+
* Minimal APIs (parameter binding, read request body)
10+
* MVC (input formatters, model)
11+
* The <xref:Microsoft.AspNetCore.Http.HttpRequestJsonExtensions> Extension methods to read the request body as JSON.
12+
13+
For most applications, a transition from Stream to PipeReader provides better performance without requiring changes in application code. But if your application has a custom converter, the converter might not handle <xref:System.Text.Json.Utf8JsonReader.HasValueSequence%2A?displayProperty=nameWithType> correctly. If it doesn't, the result could be errors such as <xref:System.ArgumentOutOfRangeException> or missing data when deserializing. You have the following options for getting your converter to work without PipeReader-related errors.
14+
15+
### Option 1: Temporary workaround
16+
17+
The quick workaround is to go back to using Stream without PipeReader support. To implement this option, set the "Microsoft.AspNetCore.UseStreamBasedJsonParsing" AppContext switch to "true". We recommend that you do this only as a temporary workaround, and update your converter to support `HasValueSequence` as soon as possible. The switch might be removed in .NET 11. Its only purpose was to give developers time to get their converters updated.
18+
19+
### Option 2: A quick fix for `JsonConverter` implementations
20+
21+
For this fix, you allocate an array from the `ReadOnlySequence`. This example shows what the code would look like:
22+
23+
```csharp
24+
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
25+
{
26+
var span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
27+
// previous code
28+
}
29+
```
30+
31+
### Option 3: A more complicated but better performing fix
32+
33+
This fix involves setting up a separate code path for the `ReadOnlySequence` handling:
34+
35+
```csharp
36+
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
37+
{
38+
if (reader.HasValueSequence)
39+
{
40+
reader.ValueSequence;
41+
// ReadOnlySequence optimized path
42+
}
43+
else
44+
{
45+
reader.ValueSpan;
46+
// ReadOnlySpan optimized path
47+
}
48+
}
49+
```
50+
51+
For more information, see
52+
* <xref:System.Text.Json.Serialization.JsonConverter?displayProperty=nameWithType>
53+
* [github.com/dotnet/aspnetcore/pull/62895](https://github.com/dotnet/aspnetcore/pull/62895)

aspnetcore/mvc/models/model-binding.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ ms.date: 07/19/2025
88
ai-usage: ai-assisted
99
uid: mvc/models/model-binding
1010
---
11-
11+
<!-- Note the use of inline moniker tags at the end of the file. -->
1212
# Model Binding in ASP.NET Core
1313

1414
[!INCLUDE[](~/includes/not-latest-version.md)]
@@ -722,6 +722,16 @@ If an instance of the type isn't registered in the dependency injection containe
722722

723723
For nullable parameters, ensure that the parameter isn't `null` before accessing it.
724724

725+
:::moniker-end
726+
:::moniker range=">= aspnetcore-10.0"
727+
728+
## Json+PipeReader deserialization in MVC
729+
730+
[!INCLUDE [](~/includes/net10pipereader.md)]
731+
732+
:::moniker-end
733+
:::moniker range=">= aspnetcore-8.0"
734+
725735
## Additional resources
726736

727737
* [View or download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/mvc/models/model-binding/samples) ([how to download](xref:fundamentals/index#how-to-download-a-sample))
@@ -731,4 +741,3 @@ For nullable parameters, ensure that the parameter isn't `null` before accessing
731741
:::moniker-end
732742

733743
[!INCLUDE[](~/mvc/models/model-binding/includes/model-binding7.md)]
734-

0 commit comments

Comments
 (0)