dotnet / dotnet/aspnetcore

Enhance experience for auto-populating JsonSerializerContext with required types

Open
#56,021 4 comments 1 reaction 0 assignees View on GitHub
area-minimal feature-openapi NativeAOT
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 6h
Merged PRs (30d)
290

Description

### Is there an existing issue for this?

- [X] I have searched the existing issues

### Describe the bug

I was playing around with the native AoT support for the new OpenAPI feature in the .NET 9 preview.5 nightly builds (`9.0.100-preview.5.24281.15` specifically), and on rendering the document when debugging I got the following error:

```
NotSupportedException: JsonTypeInfo metadata for type 'System.Nullable`1[System.Boolean]' was not provided by TypeInfoResolver of type '[Microsoft.AspNetCore.OpenApi.OpenApiJsonSchemaContext, MartinCostello.Api.ApplicationJsonSerializerContext]'. If using source generation, ensure that all root types passed to the serializer have been annotated with 'JsonSerializableAttribute', along with any types that might be serialized polymorphically.

System.Text.Json.ThrowHelper.ThrowNotSupportedException_NoMetadataForType(Type type, IJsonTypeInfoResolver resolver)
System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type type, bool ensureConfigured, Nullable ensureNotNull, bool resolveIfMutable, bool fallBackToNearestAncestorType)
System.Text.Json.JsonSerializerOptions.GetTypeInfo(Type type)
JsonSchemaMapper.JsonSchemaMapper.GetJsonSchema(JsonSerializerOptions options, ParameterInfo parameterInfo, JsonSchemaMapperConfiguration configuration)
Microsoft.AspNetCore.OpenApi.OpenApiComponentService.CreateSchema(ValueTuple key)
System.Collections.Concurrent.ConcurrentDictionary.GetOrAdd(TKey key, Func valueFactory)
Microsoft.AspNetCore.OpenApi.OpenApiComponentService.GetOrCreateSchema(Type type, ApiParameterDescription parameterDescription)
Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetParameters(ApiDescription description)
Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOperation(ApiDescription description, HashSet capturedTags)
Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOperations(IGrouping descriptions, HashSet capturedTags)
Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOpenApiPaths(HashSet capturedTags)
Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOpenApiDocumentAsync(CancellationToken cancellationToken)
Microsoft.AspNetCore.Builder.OpenApiEndpointRouteBuilderExtensions+<>c__DisplayClass0_0+<b__0>d.MoveNext()
Microsoft.AspNetCore.Http.Generated.F56B68D2B55B5B7B373BA2E4796D897848BC0F04A969B1AF6260183E8B9E0BAF2__GeneratedRouteBuilderExtensionsCore+<>c__DisplayClass2_0+<g__RequestHandler|5>d.MoveNext()
Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware.InvokeCore(HttpContext context)
Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
MartinCostello.Api.Middleware.CustomHttpHeadersMiddleware.Invoke(HttpContext context) in CustomHttpHeadersMiddleware.cs
```

None of my API models use `bool?`, so I was a bit confused as to what was causing the problem.

Doing a find in Visual Studio for `bool?` lead me to an optional query string parameter on one of my endpoints: [code](https://github.com/martincostello/api/blob/aa691000a84f23ee18f06420fd3b3ee1ad616968/src/API/ApiModule.cs#L152)

I'm not sure what, if anything, can be done here, but the local developer experience digging through as to what needs to be added to my custom `JsonSerializerContext` (in this case adding `[JsonSerializable(typeof(bool?))]`) for things to render isn't great, and I imagine could be quite frustrating in a larger application.

It's also a bit confusing at first, as when I think of custom JSON serialization for AoT I think of custom types, not built-in primitive parameters. It's not needed for Request Delegate Generator to work for the actual API endpoints, for example.

### Expected Behavior

Either:

- things "just work" (generate a custom `JsonSerializerContext` with a source generator for all the types known to be part of the API surface?)
- an analyser to help identify the things you need to add to your serialization context?
- ...?

### Steps To Reproduce

- Clone https://github.com/martincostello/api/pull/1504/commits/aa691000a84f23ee18f06420fd3b3ee1ad616968
- Open the solution in Visual Studio and start the debugger
- Perform an HTTP request to the `/openapi/api.json` endpoint

### Exceptions (if any)

```
NotSupportedException: JsonTypeInfo metadata for type 'System.Nullable`1[System.Boolean]' was not provided by TypeInfoResolver of type '[Microsoft.AspNetCore.OpenApi.OpenApiJsonSchemaContext, MartinCostello.Api.ApplicationJsonSerializerContext]'. If using source generation, ensure that all root types passed to the serializer have been annotated with 'JsonSerializableAttribute', along with any types that might be serialized polymorphically.

System.Text.Json.ThrowHelper.ThrowNotSupportedException_NoMetadataForType(Type type, IJsonTypeInfoResolver resolver)
System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type type, bool ensureConfigured, Nullable ensureNotNull, bool resolveIfMutable, bool fallBackToNearestAncestorType)
System.Text.Json.JsonSerializerOptions.GetTypeInfo(Type type)
JsonSchemaMapper.JsonSchemaMapper.GetJsonSchema(JsonSerializerOptions options, ParameterInfo parameterInfo, JsonSchemaMapperConfiguration configuration)
Microsoft.AspNetCore.OpenApi.OpenApiComponentService.CreateSchema(ValueTuple key)
System.Collections.Concurrent.ConcurrentDictionary.GetOrAdd(TKey key, Func valueFactory)
Microsoft.AspNetCore.OpenApi.OpenApiComponentService.GetOrCreateSchema(Type type, ApiParameterDescription parameterDescription)
Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetParameters(ApiDescription description)
Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOperation(ApiDescription description, HashSet capturedTags)
Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOperations(IGrouping descriptions, HashSet capturedTags)
Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOpenApiPaths(HashSet capturedTags)
Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOpenApiDocumentAsync(CancellationToken cancellationToken)
Microsoft.AspNetCore.Builder.OpenApiEndpointRouteBuilderExtensions+<>c__DisplayClass0_0+<b__0>d.MoveNext()
Microsoft.AspNetCore.Http.Generated.F56B68D2B55B5B7B373BA2E4796D897848BC0F04A969B1AF6260183E8B9E0BAF2__GeneratedRouteBuilderExtensionsCore+<>c__DisplayClass2_0+<g__RequestHandler|5>d.MoveNext()
Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware.InvokeCore(HttpContext context)
Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
MartinCostello.Api.Middleware.CustomHttpHeadersMiddleware.Invoke(HttpContext context) in CustomHttpHeadersMiddleware.cs
```

### .NET Version

9.0.100-preview.5.24281.15

### Anything else?

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.