Support per-document JsonSerializerOptions in OpenAPI schema generation
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 290
Description
## Background and Motivation
Microsoft.AspNetCore.OpenApi's `OpenApiSchemaService` uses a single, default-named `IOptions` for schema generation. This means all OpenAPI documents in the same host share the same JSON serialization settings.
For platforms that register their own APIs alongside consumer APIs in the same host (e.g., a CMS with backoffice APIs), this is a problem: configuring the default `JsonOptions` to match the platform's needs would leak those settings into consumer APIs. The only alternative is a workaround: locating the internal `OpenApiSchemaService` registration by type name, removing it from the DI container, and re-registering it with a custom `IOptions` wrapper that returns the desired named options.
See [umbraco/Umbraco-CMS/pull/21058](https://github.com/umbraco/Umbraco-CMS/pull/21058/changes#diff-7416dbdc100a3dae0edff11951c554ab2954e4853fb404b86458c693ec395380R28-R54).
This workaround is fragile because `OpenApiSchemaService` is `internal sealed`, there's no SemVer contract, so any patch release could break it. It also affects downstream consumers who may transitively bring a different package version.
We are not the only ones affected. The `dotnet/aspnet-api-versioning` library (`Asp.Versioning.OpenApi`) also needs to work with `OpenApiSchemaService` and other internal types for per-version document generation, as mentioned [here](https://github.com/dotnet/aspnet-api-versioning/discussions/1174).
Related issue: #60738 (broader design proposal about ASP.NET components relation to JSON settings).
## Proposed API
Either of these would solve the problem:
### Option A: Named `JsonOptions` support per document
`OpenApiSchemaService` is already registered as a keyed singleton using the document name as its service key. It could use that same key to resolve named `JsonOptions` via `IOptionsMonitor.Get(documentName)`, falling back to the default options if no named options are configured for that key.
This would allow platforms to register document-specific JSON options:
```csharp
builder.Services.AddOpenApi("my-api");
builder.Services.Configure("my-api", options =>
{
options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
});
```
Alternatively, `OpenApiOptions` could expose an explicit property to specify a different options name:
```csharp
builder.Services.AddOpenApi("my-api", options =>
{
options.JsonOptionsName = "MyApiJsonOptions";
});
```
### Option B: Make `OpenApiSchemaService` public (or provide a public abstraction)
Making the schema service public (or extractable via an interface) would allow platforms to register their own implementation or decorate it cleanly through standard DI patterns, without reflection on internals.
## Risks
No breaking changes, both options are additive.
With option A and using the key, the only behavioral change could be that someone already registered json options with that key and is not expecting it to be used for the open api generation, although it feels unlikely.
Contributor guide
Assessment
This issue has not been assessed yet.