Skip to content

Add warning for ASP.NET Core version < 10.0 #2451

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 25, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 39 additions & 31 deletions docs/upgrade-guide-2.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
---
title: Upgrade guide to OpenAPI.NET 2.1
description: Learn how to upgrade your OpenAPI.NET version from 1.6 to 2.0
title: Upgrade guide to OpenAPI.NET 2.0
description: Learn how to upgrade your OpenAPI.NET version from 1.6 to 2.0
author: rachit.malik
ms.author: malikrachit
ms.topic: conceptual
---

# Introduction

We are excited to announce the new version of the OpenAPI.NET library!
We are excited to announce the new version of the OpenAPI.NET library!
OpenAPI.NET v2 is a major update to the OpenAPI.NET library. This release includes a number of performance improvements, API enhancements, and support for OpenAPI v3.1.

> [!WARNING]
> If you are using this library with ASP.NET Core version `< 10.0` then you must remain on version `1.x` as it's not compatible.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn’t strictly true. It’s not compatible with the Microsoft.AspNetCore.OpenApi library, which depends on Microsoft.OpenApi v1.

If your application doesn’t use that (either directly, or transitively via a dependency such as Swashbuckle.AspNetCore), then you can use v2 with ASP.NET Core 8 and 9.

Copy link
Contributor Author

@Frulfump Frulfump Aug 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@martincostello Oh I thought there was some (non-absorbable)breaking changes affecting < ASP.NET Core 10 based on the maintainers conversation in the linked issue. Thanks I'll prepare a new PR!

(I was actually thinking about pinging you in the issue but didn't want to disturb you 😅)

Copy link
Contributor

@martincostello martincostello Aug 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's useable, it's just potentially lot of work due to the breaking changes, but other than where you depend on other dependencies using v1, it can be used. For example for Swashbuckle users, it definitely is breaking and not possible to use until we ship our release that supports v2 in November.

I'd just make the warning not so absolute in its wording.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah that makes sense, I agree. Could you prepare the PR instead I'm on a cellular connection and it's not very stable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's see how the discussion in the issue you tagged me on pans out first.


## The biggest update ever

Since the release of the first version of the OpenAPI.NET library in 2018, there has not been a major version update to the library. With the addition of support for OpenAPI v3.1 it was necessary to make some breaking changes. With this opportunity, we have taken the time to make some other improvements to the library, based on the experience we have gained supporting a large community of users for the last six years .
Since the release of the first version of the OpenAPI.NET library in 2018, there has not been a major version update to the library. With the addition of support for OpenAPI v3.1 it was necessary to make some breaking changes. With this opportunity, we have taken the time to make some other improvements to the library, based on the experience we have gained supporting a large community of users for the last six years.

## Performance Improvements

One of the key features of OpenAPI.NET is its performance. This version makes it possible to parse JSON based OpenAPI descriptions even faster. OpenAPI.NET v1 relied on the excellent YamlSharp library for parsing both JSON and YAML files. With OpenAPI.NET v2 we are relying on System.Text.Json for parsing JSON files. For YAML files, we continue to use YamlSharp to parse YAML but then convert to JsonNodes for processing. This allows us to take advantage of the performance improvements in System.Text.Json while still supporting YAML files.

In v1, instances of `$ref` were resolved in a second pass of the document to ensure the target of the reference has been parsed before attempting to resolve it. In v2, reference targets are lazily resolved when reference objects are accessed. This improves load time performance for documents that make heavy use of references.

[How does this change the behaviour of external references?]
[How does this change the behavior of external references?]

### Results

Expand Down Expand Up @@ -95,15 +98,15 @@ mySchema.AnyOf = new List<IOpenApiSchema> { otherSchema };

## Reduced Dependencies

In OpenAPI v1, it was necessary to include the Microsoft.OpenApi.Readers library to be able to read OpenAPI descriptions in either YAML or JSON. In OpenAPI.NET v2, the core Microsoft.OpenAPI library can both read and write JSON. It is only necessary to use the newly renamed [Microsoft.OpenApi.YamlReader](https://www.nuget.org/packages/Microsoft.OpenApi.YamlReader/) library if you need YAML support. This allows teams who are only working in JSON to avoid the additional dependency and therefore eliminate all non-.NET library references.
In OpenAPI v1, it was necessary to include the Microsoft.OpenApi.Readers library to be able to read OpenAPI descriptions in either YAML or JSON. In OpenAPI.NET v2, the core Microsoft.OpenAPI library can both read and write JSON. It is only necessary to use the newly renamed [Microsoft.OpenApi.YamlReader](https://www.nuget.org/packages/Microsoft.OpenApi.YamlReader/) library if you need YAML support. This allows teams who are only working in JSON to avoid the additional dependency and therefore eliminate all non-.NET library references.

Once the dependency is added, the reader needs to be added to the reader settings as demonstrated below

```csharp
var settings = new OpenApiReaderSettings();
settings.AddYamlReader();
var settings = new OpenApiReaderSettings();
settings.AddYamlReader();

var result = OpenApiDocument.LoadAsync(openApiString, settings: settings);
var result = OpenApiDocument.LoadAsync(openApiString, settings: settings);
```

## API Enhancements
Expand All @@ -117,7 +120,7 @@ var reader = new OpenApiStringReader();
var openApiDoc = reader.Read(stringOpenApiDoc, out var diagnostic);
```

The same pattern can be used for `OpenApiStreamReader` and `OpenApiTextReader`. When we introduced the `ReadAsync` methods we eliminated the use of the `out` parameter. To improve code readability, we've added deconstruction support to `ReadResult`. The properties also have been renamed to avoid confusion with their types.
The same pattern can be used for `OpenApiStreamReader` and `OpenApiTextReader`. When we introduced the `ReadAsync` methods we eliminated the use of the `out` parameter. To improve code readability, we've added deconstruction support to `ReadResult`. The properties also have been renamed to avoid confusion with their types.

```csharp
var reader = new OpenApiStreamReader();
Expand All @@ -130,7 +133,7 @@ var diagnostics = result.Diagnostics;

A `ReadResult` object acts as a tuple of `OpenApiDocument` and `OpenApiDiagnostic`.

The challenge with this approach is that the reader classes are not very discoverable and the behaviour is not actually consistent with the `*TextReader` pattern that allows incrementally reading the document. This library does not support incrementally reading the OpenAPI Document. It only reads a complete document and returns an `OpenApiDocument` instance.
The challenge with this approach is that the reader classes are not very discoverable and the behavior is not actually consistent with the `*TextReader` pattern that allows incrementally reading the document. This library does not support incrementally reading the OpenAPI Document. It only reads a complete document and returns an `OpenApiDocument` instance.

In the v2 library we are moving to the pattern used by classes like `XDocument` where a set of static `Load` and `Parse` methods are used as factory methods.

Expand All @@ -143,11 +146,11 @@ public class OpenApiDocument {
}
```

This API design allows a developer to use IDE autocomplete to present all the loading options by simply knowing the name of the `OpenApiDocument` class. Each of these methods are layered on top of the more primitive methods to ensure consistent behaviour.
This API design allows a developer to use IDE autocomplete to present all the loading options by simply knowing the name of the `OpenApiDocument` class. Each of these methods are layered on top of the more primitive methods to ensure consistent behavior.

As the YAML format is only supported when including the `Microsoft.OpenApi.YamlReader` library it was decided not to use an enum for the `format` parameter. We are considering implementing a more [strongly typed solution](https://github.com/microsoft/OpenAPI.NET/issues/1952) similar to the way that `HttpMethod` is implemented so that we have a strongly typed experience that is also extensible.
As the YAML format is only supported when including the `Microsoft.OpenApi.YamlReader` library it was decided not to use an enum for the `format` parameter. We are considering implementing a more [strongly typed solution](https://github.com/microsoft/OpenAPI.NET/issues/1952) similar to the way that `HttpMethod` is implemented so that we have a strongly typed experience that is also extensible.

When the loading methods are used without a format parameter, we will attempt to parse the document using the default JSON reader. If that fails and the YAML reader is registered, then we will attempt to read as YAML. The goal is always to provide the fastest path with JSON but still maintain the convenience of not having to care whether a URL points to YAML or JSON if you need that flexibility.
When the loading methods are used without a format parameter, we will attempt to parse the document using the default JSON reader. If that fails and the YAML reader is registered, then we will attempt to read as YAML. The goal is always to provide the fastest path with JSON but still maintain the convenience of not having to care whether a URL points to YAML or JSON if you need that flexibility.

### Additional exceptions

Expand Down Expand Up @@ -281,7 +284,7 @@ var info = schema.Metadata["foo"];

### Updates to OpenApiSchema

The OpenAPI 3.1 specification changes significantly how it leverages JSON Schema. In 3.0 and earlier, OpenAPI used a "subset, superset" of JSON Schema draft-4. This caused many problems for developers trying to use JSON Schema validation libraries with the JSON Schema in their OpenAPI descriptions. In OpenAPI 3.1, the 2020-12 draft version of JSON Schema was adopted and a new JSON Schema vocabulary was adopted to support OpenAPI specific keywords. All attempts to constrain what JSON Schema keywords could be used in OpenAPI were removed.
The OpenAPI 3.1 specification changes significantly how it leverages JSON Schema. In 3.0 and earlier, OpenAPI used a "subset, superset" of JSON Schema draft-4. This caused many problems for developers trying to use JSON Schema validation libraries with the JSON Schema in their OpenAPI descriptions. In OpenAPI 3.1, the 2020-12 draft version of JSON Schema was adopted and a new JSON Schema vocabulary was adopted to support OpenAPI specific keywords. All attempts to constrain what JSON Schema keywords could be used in OpenAPI were removed.

#### New keywords introduced in 2020-12

Expand All @@ -308,24 +311,24 @@ public bool UnevaluatedProperties { get; set;}
#### Changes to existing keywords

```csharp
public string? ExclusiveMaximum { get; set; } // type changed to reflect the new version of JSON schema
public string? ExclusiveMaximum { get; set; } // type changed to reflect the new version of JSON schema
public string? ExclusiveMinimum { get; set; } // type changed to reflect the new version of JSON schema
public JsonSchemaType? Type { get; set; } // Was string, now flagged enum
public JsonSchemaType? Type { get; set; } // Was string, now flagged enum
public string? Maximum { get; set; } // type changed to overcome double vs decimal issues
public string? Minimum { get; set; } // type changed to overcome double vs decimal issues

public JsonNode Default { get; set; } // Type matching no longer enforced. Was IOpenApiAny
public bool ReadOnly { get; set; } // No longer has defined semantics in OpenAPI 3.1
public bool WriteOnly { get; set; } // No longer has defined semantics in OpenAPI 3.1
public JsonNode Default { get; set; } // Type matching no longer enforced. Was IOpenApiAny
public bool ReadOnly { get; set; } // No longer has defined semantics in OpenAPI 3.1
public bool WriteOnly { get; set; } // No longer has defined semantics in OpenAPI 3.1

public JsonNode Example { get; set; } // No longer IOpenApiAny
public JsonNode Example { get; set; } // No longer IOpenApiAny
public IList<JsonNode> Examples { get; set; }
public IList<JsonNode> Enum { get; set; }
public OpenApiExternalDocs ExternalDocs { get; set; } // OpenApi Vocab
public bool Deprecated { get; set; } // OpenApi Vocab
public OpenApiXml Xml { get; set; } // OpenApi Vocab
public OpenApiExternalDocs ExternalDocs { get; set; } // OpenApi Vocab
public bool Deprecated { get; set; } // OpenApi Vocab
public OpenApiXml Xml { get; set; } // OpenApi Vocab

public IDictionary<string, object> Metadata { get; set; } // Custom property bag to be used by the application, used to be named annotations
public IDictionary<string, object> Metadata { get; set; } // Custom property bag to be used by the application, used to be named annotations
```

#### OpenApiSchema methods
Expand All @@ -349,7 +352,8 @@ public class OpenApiSchema : IMetadataContainer, IOpenApiExtensible, IOpenApiRef
There are a number of new features in OpenAPI v3.1 that are now supported in OpenAPI.NET.

### JsonSchema Dialect and BaseUri in OpenApiDocument
To enable full compatibility with JSON Schema, the `OpenApiDocument` class now supports a `JsonSchemaDialect` property. This property specifies the JSON Schema dialect used throughout the document, using a URI. By explicitly declaring the dialect, tooling can be directed to use a JSON Schema version other than the default [2020-12 draft](https://json-schema.org/draft/2020-12/json-schema-core.html). However, OpenAPI.NET does not guarantee compatibility with versions other than 2020-12.

To enable full compatibility with JSON Schema, the `OpenApiDocument` class now supports a `JsonSchemaDialect` property. This property specifies the JSON Schema dialect used throughout the document, using a URI. By explicitly declaring the dialect, tooling can be directed to use a JSON Schema version other than the default [2020-12 draft](https://json-schema.org/draft/2020-12/json-schema-core.html). However, OpenAPI.NET does not guarantee compatibility with versions other than 2020-12.

In addition, a `BaseUri` property has been added to represent the identity of the OpenAPI document. If the document’s identity is not provided or cannot be determined at based on its ___location, this property will be set to a generated placeholder URI.

Expand All @@ -375,7 +379,7 @@ public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible, IMetada

```csharp

public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible, IOpenApiMetadataContainer
public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible, IOpenApiMetadataContainer
{
public IDictionary<string, OpenApiPathItem>? Webhooks { get; set; } = new Dictionary<string, OpenApiPathItem>();
}
Expand Down Expand Up @@ -510,7 +514,7 @@ string json = await document.SerializeAsync(OpenApiSpecVersion.OpenApi3_0, OpenA

```csharp
// Before (1.6)
var outputString = openApiDocument.Serialize(OpenApiSpecVersion.OpenApi2_0, OpenApiFormat.Json);
var outputString = openApiDocument.Serialize(OpenApiSpecVersion.OpenApi2_0, OpenApiFormat.Json);

// After (2.0)
var outputString = await openApiDocument.SerializeAsync(OpenApiSpecVersion.OpenApi2_0, OpenApiConstants.Json);
Expand All @@ -521,6 +525,7 @@ var outputString = await openApiDocument.SerializeAsync(OpenApiSpecVersion.OpenA
In v2.0, the Type property in `OpenApiSchema` is now defined as a flaggable enum, allowing consumers to swap nullable for type arrays.

**Example:**

```csharp
// v1.6.x
var schema = new OpenApiSchema
Expand All @@ -533,7 +538,7 @@ var schema = new OpenApiSchema
// bitwise OR(|) - combines flags to allow multiple types
var schema = new OpenApiSchema
{
Type = JsonSchemaType.String | JsonSchemaType.Null
Type = JsonSchemaType.String | JsonSchemaType.Null
}

// bitwise NOT(~) - inverts bits; filters out null flag
Expand All @@ -545,7 +550,7 @@ var schema = new OpenApiSchema
// bitwise AND(&) - intersects flags to check for a specific type
var schema = new OpenApiSchema
{
Type = (JsonSchemaType.String & JsonSchemaType.Null) == JsonSchemaType.Null
Type = (JsonSchemaType.String & JsonSchemaType.Null) == JsonSchemaType.Null
}

```
Expand Down Expand Up @@ -588,6 +593,7 @@ This resolver class has been removed in favor of a more streamlined resolution m
### Visitor and Validator now pass an interface model

**Example:**

```csharp
//v1.6.x
public override void Visit(OpenApiParameter parameter){}
Expand All @@ -605,6 +611,7 @@ All the `IEffective` and `GetEffective` infrastructure in the models have been r
Copy constructors for referenceable components have been made internal, a new `CreateShallowCopy()` method has been exposed on these models to facilitate cloning.

**Example:**

```csharp
var schema = new OpenApiSchema();
var schemaCopy = schema.CreateShallowCopy();
Expand All @@ -619,6 +626,7 @@ The redundant _style property on the Parameter model has been removed to simplif
Discriminator mappings have been updated from using a `Dictionary<string, string>` to a `Dictionary<string, OpenApiSchemaReference>`. This change improves the handling of discriminator mappings by referencing OpenAPI schema components more explicitly, which enhances schema resolution.

**Example:**

```csharp
// v1.6.x
Discriminator = new()
Expand Down Expand Up @@ -660,5 +668,5 @@ OpenApiSchemaReference schemaRef = new OpenApiSchemaReference("MySchema")

## Feedback

If you have any feedback please file a GitHub issue [here](https://github.com/microsoft/OpenAPI.NET/issues)
If you have any feedback please file [a new GitHub issue](https://github.com/microsoft/OpenAPI.NET/issues)
The team is looking forward to hear your experience trying the new version and we hope you have fun busting out your OpenAPI 3.1 descriptions.