OpenAPI and API Versioning
|
This section documents ASP.NET Core on .NET 10 (LTS), the current release — the minimal hosting model, the middleware pipeline, dependency injection, Minimal APIs, MVC & Razor Pages, Blazor with the current render modes, SignalR and gRPC, EF Core, ASP.NET Core Identity and policy-based authorization, output caching, rate limiting, and Native-AOT-aware building — as described by the official documentation at Microsoft Learn, which is the reference these pages are written and verified against. This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. .NET ships a major release every November and its APIs continue to evolve: the examples here target .NET 10 / C# 14. This section’s bibliography lists the reference material consulted while preparing these pages. |
The built-in Microsoft.AspNetCore.OpenApi package generates an OpenAPI document describing both
Minimal API and controller
endpoints, with no separate reflection-based tool required.
Adding OpenAPI generation
// dotnet add package Microsoft.AspNetCore.OpenApi
builder.Services.AddOpenApi();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi(); // serves /openapi/v1.json
}
app.MapGet("/orders/{id:int}", GetOrder)
.WithName("GetOrder")
.WithSummary("Fetch a single order")
.ProducesProblem(StatusCodes.Status404NotFound);
On controllers, [ProducesResponseType<OrderDto>(StatusCodes.Status200OK)] and
[ProducesResponseType(StatusCodes.Status404NotFound)] describe responses the same way. See
OpenAPI support in ASP.NET Core.
OpenAPI 3.1 and JSON Schema 2020-12
than the OpenAPI-specific subset earlier versions used — nullable types are expressed as a type array
(["string", "null"]) instead of a separate nullable: true keyword, and constructs like examples (plural)
and const are natively available. Pin an older version explicitly if a downstream tool still expects 3.0:
builder.Services.AddOpenApi(o => o.OpenApiVersion = Microsoft.OpenApi.OpenApiSpecVersion.OpenApi3_0);
YAML output
Request YAML instead of JSON by giving the endpoint a .yaml/.yml suffix:
app.MapOpenApi("/openapi/{documentName}.yaml");
Both formats describe the same document — pick whichever a consuming tool expects.
XML doc comments
Enable the project’s XML documentation file and .NET 10 folds <summary>, <param>, <returns>, and
<remarks> comments into the generated document as operation/parameter descriptions:
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);CS1591</NoWarn> <!-- don't warn on every undocumented public member -->
</PropertyGroup>
/// <summary>Fetches a single order by id.</summary>
/// <param name="id">The order id.</param>
/// <returns>The order, or 404 if it does not exist.</returns>
app.MapGet("/orders/{id:int}", GetOrder);
Document, operation, and schema transformers
Transformers post-process the generated document — add a security scheme, tweak a summary, redact a schema — without hand-editing the output:
builder.Services.AddOpenApi(o =>
{
o.AddDocumentTransformer((document, context, ct) =>
{
document.Info.Title = "Orders API";
document.Info.Version = "v1";
return Task.CompletedTask;
});
o.AddOperationTransformer((operation, context, ct) =>
{
operation.Summary ??= context.Description.ActionDescriptor.DisplayName;
return Task.CompletedTask;
});
o.AddSchemaTransformer((schema, context, ct) =>
{
if (context.JsonTypeInfo.Type == typeof(OrderDto))
{
schema.Description = "An order as returned to API consumers.";
}
return Task.CompletedTask;
});
});
Implement IOpenApiDocumentTransformer, IOpenApiOperationTransformer, or IOpenApiSchemaTransformer as a
class (resolved from DI, so it can take constructor dependencies) instead of a lambda when the logic grows.
See Customize OpenAPI
documents.
IOpenApiDocumentProvider
Inject IOpenApiDocumentProvider to obtain the generated OpenApiDocument in code — for example to write it
to a file at build time, feed a client generator, or serve it from a non-default endpoint:
public sealed class OpenApiExportService(IOpenApiDocumentProvider provider)
{
public async Task<string> GetJsonAsync(CancellationToken ct)
{
var document = await provider.GetOpenApiDocumentAsync(ct);
return document.SerializeAsJson(Microsoft.OpenApi.OpenApiSpecVersion.OpenApi3_1);
}
}
Serving a UI: Scalar and Swagger UI
The Microsoft.AspNetCore.OpenApi package produces the document only; add a UI on top of it:
// dotnet add package Scalar.AspNetCore
app.MapScalarApiReference(); // serves an interactive UI at /scalar/v1
Swagger UI (via Swashbuckle’s Swashbuckle.AspNetCore.SwaggerUI package) and NSwag’s bundled UI both work the
same way, pointed at the /openapi/v1.json endpoint. See
Using generated
OpenAPI documents.
Generating clients
-
NSwag — generates a typed C#/TypeScript HTTP client from the OpenAPI document (
nswag openapi2csclient). -
Kiota — Microsoft’s cross-language client generator (
kiota generate --openapi openapi.json --language CSharp), used heavily with Microsoft Graph-style APIs but works against any OpenAPI 3.x document. -
Refit — an alternative that hand-declares the client interface rather than generating it from the document; see HTTP Client and Resilience.
API versioning
The Asp.Versioning.Mvc (controllers) and Asp.Versioning.Http (Minimal APIs) packages support versioning by
URL segment, query string, header, or media type:
// dotnet add package Asp.Versioning.Mvc
builder.Services.AddApiVersioning(o =>
{
o.DefaultApiVersion = new ApiVersion(1);
o.AssumeDefaultVersionWhenUnspecified = true;
o.ReportApiVersions = true;
}).AddMvc();
[ApiVersion(1)]
[ApiVersion(2)]
[Route("api/v{version:apiVersion}/[controller]")]
public sealed class OrdersController : ControllerBase
{
[HttpGet, MapToApiVersion(2)]
public IActionResult GetV2() => Ok(new { schema = "v2" });
}
Each versioned Asp.Versioning-aware endpoint can contribute its own OpenAPI document (one document per API
version) via AddApiExplorer() combined with AddOpenApi(…) per version group. See
OpenAPI and API
versioning and the Asp.Versioning project docs.