OpenAPI is one of those parts of an ASP.NET Core application that often works quietly in the background. You build an endpoint, define a request model, add response types, and the framework generates an API description for you. Most developers only look at the generated document when they need Swagger UI, client generation, testing, or API documentation.
With OpenAPI 3.2, there are a few things worth checking more carefully. The important part is not simply changing a version number. The generated document can contain structures that older tools do not understand, and applications that customize OpenAPI generation may also be affected by changes in the underlying Microsoft.OpenApi library.
ASP.NET Core provides built-in OpenAPI document generation through the Microsoft.AspNetCore.OpenApi package. In .NET 11, generated documents use OpenAPI 3.2 by default, while earlier OpenAPI versions can still be selected explicitly when compatibility with existing tooling is required.
This article looks at the practical checks developers should make when working with OpenAPI 3.2 in an ASP.NET Core application.
What OpenAPI 3.2 Changes for ASP.NET Core Developers
OpenAPI is a specification for describing HTTP APIs in a machine-readable format. The document describes things such as:
- Available endpoints
- HTTP methods
- Parameters
- Request bodies
- Response types
- Authentication requirements
- Data models
- Content types
ASP.NET Core uses endpoint metadata and API descriptions to generate this document.
The important change is that OpenAPI 3.2 is now a supported document format in the ASP.NET Core OpenAPI stack, and it becomes the default generated format in .NET 11.
For a normal application, you may not notice much difference immediately. Existing endpoints can continue to generate documentation in the usual way.
The differences become more important when you use custom OpenAPI tooling, document transformers, build-time document generation, streaming APIs, custom HTTP methods, or code that directly works with Microsoft.OpenApi types.
Check Which OpenAPI Version Your Application Generates
The first thing to check is the actual OpenAPI version being generated.
A basic ASP.NET Core setup can look like this:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.MapGet("/products", () =>
{
return new[]
{
new { Id = 1, Name = "Keyboard" },
new { Id = 2, Name = "Mouse" }
};
});
app.Run();
With the default configuration in .NET 11, the generated document targets OpenAPI 3.2.
The document is normally exposed through an endpoint such as:
/openapi/v1.json
The important point is that generating an OpenAPI document and displaying it in a UI are two separate things.
ASP.NET Core generates the document, but interactive tools such as Swagger UI or Scalar are not included by default. They can be added separately when needed.
Check Your Existing API Tooling
This is probably the most practical check before switching an existing application to OpenAPI 3.2.
Your ASP.NET Core application may generate the document correctly while another part of your development pipeline is not ready for it.
For example, your workflow might look like this:
ASP.NET Core API
|
v
OpenAPI 3.2 document
|
+---- Swagger UI
|
+---- Client generator
|
+---- API testing tool
|
+---- Contract testing
|
+---- External documentation
The ASP.NET Core application is only one part of this chain.
If your client generator or API management platform expects OpenAPI 3.0 or 3.1, generating 3.2 can introduce compatibility problems.
This is why you should test the generated document with the tools that consume it instead of assuming that a valid OpenAPI 3.2 document will work everywhere.
If a downstream tool does not yet understand OpenAPI 3.2, ASP.NET Core allows you to generate an earlier version explicitly.
For example:
using Microsoft.OpenApi;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi(options =>
{
options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_1;
});
This is useful when your application needs to support an existing toolchain while you gradually upgrade the rest of the system.
Check Custom OpenAPI Transformers
Custom OpenAPI transformers deserve special attention.
ASP.NET Core supports three useful transformer types:
- Document transformers
- Operation transformers
- Schema transformers
A document transformer can modify the complete document. An operation transformer can modify individual API operations, while a schema transformer can modify generated request and response schemas.
For example:
builder.Services.AddOpenApi(options =>
{
options.AddDocumentTransformer((document, context, cancellationToken) =>
{
document.Info = new()
{
Title = "Product API",
Version = "v1",
Description = "API for managing products."
};
return Task.CompletedTask;
});
});
This type of customization is common in production applications.
You might use transformers to add authentication information, standard response codes, custom descriptions, headers, tags, or organization-specific metadata.
The problem is that code written against older versions of Microsoft.OpenApi may not compile or behave the same way after the underlying library moves to the newer 3.x API model.
Microsoft specifically calls out changes affecting custom document, operation, and schema transformers when moving from Microsoft.OpenApi 2.x to 3.x.
So if your application contains custom transformer code, do not treat the OpenAPI version change as a simple configuration change.
Check Microsoft.OpenApi Package Changes
This is an important distinction.
OpenAPI 3.2 is the specification version.
Microsoft.OpenApi is the .NET library used by the ASP.NET Core OpenAPI implementation.
They are related, but they are not the same thing.
The Microsoft.OpenApi 3.x API introduced changes to its object model. For example, several document objects are now represented through interfaces rather than relying only on concrete classes.
Code that previously looked like this:
OpenApiSchema schema = ...;
may need to work with interface-based abstractions in newer APIs.
Similarly, older code using types such as:
OpenApiString
OpenApiAny
may require changes when moving to the newer library model. Microsoft recommends reviewing transformer code and schema manipulation code during the migration.
This matters particularly for applications that do more than simply generate an OpenAPI document.
If your application only calls:
builder.Services.AddOpenApi();
the migration is usually much simpler.
If your application directly manipulates generated OpenAPI objects, expect more work.
Check Custom Schemas
Schema generation is another area worth testing.
Suppose you have a request model like this:
public sealed class CreateProductRequest
{
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
public int Quantity { get; set; }
}
Your OpenAPI document contains a schema describing this model.
That schema can be consumed by:
- Client generators
- Validation tools
- Documentation systems
- Contract tests
- API gateways
- Other services
A small schema difference can therefore have a larger impact than expected.
If you have custom schema transformers, review them carefully.
For example:
builder.Services.AddOpenApi(options =>
{
options.AddSchemaTransformer((schema, context, cancellationToken) =>
{
if (context.JsonTypeInfo.Type == typeof(decimal))
{
schema.Format = "decimal";
}
return Task.CompletedTask;
});
});
Schema transformers are designed for exactly this kind of customization.
After upgrading, compare the generated schemas for important request and response models rather than checking only whether the application starts.
Check Nullable Types and JSON Schema Behavior
OpenAPI 3.1 introduced stronger alignment with JSON Schema, and OpenAPI 3.2 continues in that direction.
This can affect how nullable values and schemas appear in the generated document.
For example, an older document might represent nullability using a dedicated nullable property.
Newer OpenAPI documents can represent nullability using JSON Schema-compatible type information.
That matters when a generated OpenAPI document is used by another system to generate code.
A property that looks slightly different in the OpenAPI document can result in a different generated type in a client application.
This is why generated schemas should be treated as part of your API contract.
Do not only test:
GET /products
Also inspect the generated schema for:
CreateProductRequest
ProductResponse
ErrorResponse
PagedResponse<Product>
These are the parts most likely to affect generated client code.
Check HTTP QUERY and Other Operations
OpenAPI 3.2 also expands how certain HTTP operations can be described.
One example is the HTTP QUERY method.
ASP.NET Core can already work with custom HTTP method strings through routing APIs such as MapMethods. OpenAPI 3.2 provides a dedicated way to describe QUERY operations in the OpenAPI document.
For example, an application could define an endpoint using:
app.MapMethods(
"/search",
new[] { "QUERY" },
async (HttpRequest request) =>
{
// Process the search request.
return Results.Ok();
});
If your application uses unusual HTTP methods, inspect the generated OpenAPI document.
OpenAPI 3.2 has specific structures for operations that were not represented as fixed fields in earlier versions.
This becomes important for APIs that use custom methods rather than only the usual:
GET
POST
PUT
PATCH
DELETE
Most applications will never need this feature, but API frameworks and specialized services may.
Check Server-Sent Events
OpenAPI 3.2 also improves the description of streaming event responses.
ASP.NET Core can expose Server-Sent Events using typed event data:
app.MapGet("/todos/stream", (
CancellationToken cancellationToken) =>
{
return TypedResults.ServerSentEvents(
GetTodosAsync(cancellationToken));
});
static async IAsyncEnumerable<SseItem<Todo>> GetTodosAsync(
[EnumeratorCancellation] CancellationToken cancellationToken)
{
foreach (var todo in Todos.All)
{
yield return new SseItem<Todo>(todo);
await Task.Delay(1000, cancellationToken);
}
}
The generated OpenAPI 3.2 document can describe the event payload using the itemSchema structure for text/event-stream responses.
This is useful because documentation for streaming APIs has traditionally been less straightforward than documentation for ordinary JSON request/response APIs.
If your application exposes SSE endpoints, inspect the generated OpenAPI document and verify that the event payload is described the way your client tooling expects.
Check Build-Time OpenAPI Generation
Some teams generate OpenAPI documents during the build rather than generating them only when the application is running.
This is useful when the document is:
- Stored in source control
- Used for contract testing
- Published as static documentation
- Used by client generation
- Reviewed as part of a pull request
ASP.NET Core supports build-time OpenAPI generation through the Microsoft.Extensions.ApiDescription.Server package.
You can also specify which OpenAPI version should be generated during the build.
For example:
<PropertyGroup>
<OpenApiGenerateDocumentsOptions>
--openapi-version OpenApi3_1
</OpenApiGenerateDocumentsOptions>
</PropertyGroup>
This gives you more control when the application runtime and the consuming toolchain have different compatibility requirements.
If your CI pipeline validates the OpenAPI document, make sure the pipeline is testing the same version that your application is expected to publish.
Check Your API Contract Tests
OpenAPI should not be treated only as documentation.
For production APIs, the generated document can be part of the API contract.
A useful CI pipeline can follow a flow like this:
Build application
|
v
Generate OpenAPI document
|
v
Validate document
|
v
Compare against expected contract
|
v
Run API tests
|
v
Publish artifact
This catches accidental changes to endpoint contracts before they reach production.
For example, a developer might change:
public decimal Price { get; set; }
to:
public string Price { get; set; } = string.Empty;
The application may still compile and some tests may still pass.
But the OpenAPI schema has changed.
A generated client may now receive a string instead of a numeric value.
Contract validation helps detect these changes earlier.
Common Mistakes to Avoid
Assuming OpenAPI 3.2 Is Only a Version Number
It is not just a label.
The document structure and schema behavior can change, and downstream tools need to understand the format.
Upgrading Without Checking Transformers
Custom transformers are one of the areas most likely to require code changes because of the Microsoft.OpenApi API changes.
Review all code that directly accesses OpenAPI document objects.
Testing Only the API Application
The API itself may work perfectly while your client generator, documentation platform, or API gateway rejects the generated document.
Always test the complete toolchain.
Forgetting Generated Schemas
Developers often check whether endpoints appear in the document but ignore request and response schemas.
Those schemas are part of your API contract and deserve the same attention as routes.
Assuming Swagger UI Is Part of ASP.NET Core
ASP.NET Core's built-in OpenAPI support generates the specification. An interactive UI is a separate concern and needs to be added independently.
A Practical OpenAPI 3.2 Checklist
Before moving an existing ASP.NET Core application to OpenAPI 3.2, check these areas:
| Area |
What to Check |
| OpenAPI version |
Confirm which version your application generates |
| Client generators |
Verify OpenAPI 3.2 compatibility |
| Swagger or API UI |
Confirm the UI supports the generated document |
| Microsoft.OpenApi |
Review package and API changes |
| Transformers |
Test document, operation, and schema transformers |
| Schemas |
Compare important request and response models |
| Nullable types |
Check generated JSON Schema behavior |
| Custom HTTP methods |
Verify QUERY or other operations |
| SSE |
Check streaming response schemas |
| Build pipeline |
Test build-time OpenAPI generation |
| Contract tests |
Validate the generated document in CI |
This checklist is more useful than simply checking whether the application starts successfully after the upgrade.
When You Should Stay on OpenAPI 3.1
There is no requirement to immediately move every application to OpenAPI 3.2.
If your API depends on tooling that does not yet support 3.2, keeping the generated document at 3.1 can be the safer choice.
For example:
builder.Services.AddOpenApi(options =>
{
options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_1;
});
This gives the application a controlled compatibility boundary.
The important thing is to make the choice deliberately.
Use OpenAPI 3.2 when your application and surrounding tooling support it. Use an earlier version when compatibility is more important.
Best Practices
Keep the generated OpenAPI document under regular review rather than treating it as a file that only exists for Swagger UI.
Use the generated document in CI where practical. This makes API contract changes visible during development instead of discovering them after a client application breaks.
Keep custom OpenAPI transformations small and focused. If a transformer contains a large amount of logic, it becomes harder to maintain when the underlying OpenAPI library changes.
Test generated schemas for important business models. In many applications, schema compatibility matters more than the endpoint list itself.
Finally, do not upgrade the OpenAPI version independently of the tools that consume the document. The API description is part of a larger developer workflow, and compatibility needs to be checked across that workflow.
Summary
OpenAPI 3.2 brings useful improvements to ASP.NET Core, but the main migration concern is compatibility.
Check your generated document, custom transformers, schemas, client generators, API tooling, and CI pipeline before switching versions. If your existing tools are not ready, ASP.NET Core also lets you generate an earlier OpenAPI version explicitly.
Join the conversation! Your thoughts help the community grow.