-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Description
Background and Motivation
As described in #47548, ASP.NET has some internal logic around how it serializes objects to JSON for Minimal APIs and MVC. When fixing this issue in #47859, I noticed that this logic is spread out between:
- MVC's SystemTextJsonOutputFormatter
- HttpResultsHelper
- ExecuteHandlerHelper (shared between Http.Extensions and Routing)
- RequestDelegateGenerator generated code
The logic for all 4 looks like:
aspnetcore/src/Shared/RouteHandlers/ExecuteHandlerHelper.cs
Lines 39 to 57 in 6d30638
public static Task WriteJsonResponseAsync<T>(HttpResponse response, T? value, JsonTypeInfo<T> jsonTypeInfo) | |
{ | |
var runtimeType = value?.GetType(); | |
if (jsonTypeInfo.ShouldUseWith(runtimeType)) | |
{ | |
// In this case the polymorphism is not | |
// relevant for us and will be handled by STJ, if needed. | |
return HttpResponseJsonExtensions.WriteAsJsonAsync(response, value!, jsonTypeInfo, default); | |
} | |
// Since we don't know the type's polymorphic characteristics | |
// our best option is to serialize the value as 'object'. | |
// call WriteAsJsonAsync<object>() rather than the declared type | |
// and avoid source generators issues. | |
// https://github.com/dotnet/aspnetcore/issues/43894 | |
// https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-polymorphism | |
return response.WriteAsJsonAsync<object?>(value, jsonTypeInfo.Options); | |
} |
with the "ShouldUseWith" logic:
aspnetcore/src/Shared/Json/JsonSerializerExtensions.cs
Lines 13 to 17 in 6d30638
public static bool HasKnownPolymorphism(this JsonTypeInfo jsonTypeInfo) | |
=> jsonTypeInfo.Type.IsSealed || jsonTypeInfo.Type.IsValueType || jsonTypeInfo.PolymorphismOptions is not null; | |
public static bool ShouldUseWith(this JsonTypeInfo jsonTypeInfo, [NotNullWhen(false)] Type? runtimeType) | |
=> runtimeType is null || jsonTypeInfo.Type == runtimeType || jsonTypeInfo.HasKnownPolymorphism(); |
If users want to have this same serialization behavior, they would have to write that same logic in their app/library. Also, we need to encode this logic in the source generator, which means it isn't as serviceable because if we need to fix a bug in it, the dev needs to rebuild their app to get the fix.
We should come up with an API that we can shared code between these 4 places, and allow customers to serialize objects with the same behavior as how MVC and Minimal APIs does.
Proposed API
TBD
Usage Examples
TBD
Alternative Designs
Risks
The name of the API is a risk at confusing people what the difference between our existing APIs and this one do.