dotnet / dotnet/aspnetcore

Support per-document JsonSerializerOptions in OpenAPI schema generation

Open
#66,340 1 comment 2 reactions 0 assignees View on GitHub
api-proposal api-suggestion area-minimal feature-openapi
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

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.