[API Proposal]: STJ `SystemTextJsonOutputFormatter` output type selector
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 290
Description
### Background and motivation
Right now the default `SystemTextJsonOutputFormatter` internally decides what type to serialize (in `WriteResponseBodyAsync`). In my case I'd like to keep the controlers response type (an Interface) that now gets broken down to it's actual class.
Right now the type to serialize gets chosen here: https://github.com/dotnet/aspnetcore/blob/333629e6c3d4ee301bb5985f0de66f447f6226ba/src/Mvc/Mvc.Core/src/Formatters/SystemTextJsonOutputFormatter.cs#L74
and checked here: https://github.com/dotnet/aspnetcore/blob/333629e6c3d4ee301bb5985f0de66f447f6226ba/src/Mvc/Mvc.Core/src/Formatters/SystemTextJsonOutputFormatter.cs#L91
It'd be great to have an overrideable method where the `jsonTypeInfo` is selected.
### API Proposal
```
protected JsonTypeInfo? GetTypeInfo(OutputFormatterWriteContext context)
{
// context.ObjectType reflects the declared model type when specified.
// For polymorphic scenarios where the user declares a return type, but returns a derived type,
// we want to serialize all the properties on the derived type. This keeps parity with
// the behavior you get when the user does not declare the return type.
// To enable this our best option is to check if the JsonTypeInfo for the declared type is valid,
// if it is use it. If it isn't, serialize the value as 'object' and let JsonSerializer serialize it as necessary.
JsonTypeInfo? jsonTypeInfo = null;
if (context.ObjectType is not null)
{
var declaredTypeJsonInfo = SerializerOptions.GetTypeInfo(context.ObjectType);
var runtimeType = context.Object?.GetType();
if (declaredTypeJsonInfo.ShouldUseWith(runtimeType))
{
jsonTypeInfo = declaredTypeJsonInfo;
}
}
return jsonTypeInfo;
}
```
### API Usage
```
protected override JsonTypeInfo? GetTypeInfo(OutputFormatterWriteContext context)
{
if (context.ObjectType?.IsInterface == true) { return SerializerOptions.GetTypeInfo(context.ObjectType); }
return base.GetTypeInfo(context);
}
```
### Alternative Designs
_No response_
### Risks
_No response_
Contributor guide
Assessment
This issue has not been assessed yet.