NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
NuGet · #491 most downloaded on NuGet
The API Explorer extensions for ASP.NET Core API Versioning.
Last release 2 months ago
06 Aug 2026
Ships unpredictably
gaps range from 2 weeks to 1.8 years
Some releases are documented
notes for 8 of 17 stable releases
Nothing withdrawn
no release was ever pulled
4 years old
17 releases · first in 2022
One column per quarter.
Bump patched version due to transitive dependency
Microsoft.OpenApi was updated to 2.7.5 due to a vulnerability and pinned to below 3.0.0 after a major version incompatibility
This release includes some big new features but is fully backward compatible with 10.0.0. The new features include versioned model member filtering, Roslyn analyzers, gRPC preview support, and a number of servicing patches since the previous release.
'.' no longer succeeds silently'-'IProblemDetailsWriter is preserved by AddApiVersioning() (#1191)ApiVersionRange type for matching a set of API versions using the same interval notation as a package version
1.0 → x ≥ 1.0[1.0] → x == 1.0(1.0,) → x > 1.0(,1.0] → x ≤ 1.0[1.0,2.0) → 1.0 ≤ x < 2.0ApiVersionRange.Any and ApiVersionRange.Empty are provided forVisibleInApiVersionAttribute indicates the range of API versions a data member is visible in; for example,[VisibleInApiVersion("2.0")]IAnnotation<TKey, TValue> abstraction for associating out-of-band metadata with a member[StringSyntax] is now applied to API version inputs so the IDE and analyzers understand them; the recognizedApiVersion, ApiVersionRange, and ApiVersionFormatAPI Versioning now ships Roslyn analyzers. There is no new package to install — the core rules are packed into Asp.Versioning.Abstractions and the API rules are packed into Asp.Versioning.Http, so any application that already references API Versioning picks them up transitively.
There is an initial set of 31 rules. You can find all of the rule information in the new diagnostics wiki topic.
Notes:
helpLinkUri that resolves to its documentation page.editorconfig as usual<PropertyGroup>
<EnableApiVersioningAnalyzers>false</EnableApiVersioningAnalyzers>
</PropertyGroup>ExcludeAssets="analyzers" on a PackageReference will not work because the package is also reached throughASP.NET Web API (Classic) is not currently supported. If there is demand, I will consider the support, but I presume
little new development is happening on the older platform.
Data members can now be versioned independently of the endpoint that returns them. Annotate a property with [VisibleInApiVersion] and the member is omitted from responses for API versions outside the range:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
[VisibleInApiVersion( "2.0" )]
public Address? HomeAddress { get; set; }
[VisibleInApiVersion( "[1.0,2.0)" )]
public string? LegacyEmail { get; set; }
}AddApiVersioning() now registers IHttpContextAccessor so the requested API version is available during[VisibleInApiVersion] is part of the core abstractions and can be used in your model libraries without anyVersionedModelMetadata, VersionedModelMetadataProvider, and DelegatingModelMetadata types<remarks> now takes precedence over <description><b> and <i> are converted to and retained as Markdown<a href="..."/> is converted to and retained as a hyperlink<paramref name="..."/> is rendered as inline code<list>, <item>, <term>, <description>, <value>, and <example> are supported<inheritdoc/> is resolved for summaries<code> blocks are properly closedTwo new packages add API Versioning to gRPC services: Asp.Versioning.Grpc and Asp.Versioning.Grpc.ApiExplorer. This is a new set of features that will run in preview to give gRPC service authors a chance to try things out and report any issues or gaps.
The following is a basic example showing all of the parts coming together.
services.AddApiVersioning()
.AddGrpc()
.AddGrpcApiExplorer()
.AddOpenApi();
var people = app.NewVersionedApi( "People" );
people.MapGrpcService<PeopleService>()
.HasApiVersion( 1.0 )
.HasApiVersion( 2.0 )
.HasApiVersion( 3.0 );asp/api/annotations.proto:
import "asp/api/annotations.proto";
message Person {
int32 id = 1;
string first_name = 2;
string last_name = 3;
Address home_address = 4 [(asp.api.version) = "2.0"];
string phone = 5 [(asp.api.version) = "3.0"];
}repeated, so a field split across disjoint ranges repeats the option1.0 can neither see nor post a field that was introduced in 3.0The gRPC OpenAPI Example demonstrates an end-to-end working solution.
Asp.Versioning.Abstractions and Asp.Versioning.Http, which.editorconfig, or<EnableApiVersioningAnalyzers>false</EnableApiVersioningAnalyzers> is set. Before these rules existed, anAddApiVersioning() now calls AddHttpContextAccessor(). This is additive and should be transparent, but it does meanIHttpContextAccessor is registered in applications that previously did not have itThe wiki has served the community well for many years, but it had gotten tired and it was due for some much needed love and updates. I've reworked the wiki into a new GitHub Pages site using mdBook.
Why change?
It certainly possible that some links or content are incorrect after the migration. Please report any errors or submit a pull request
and they will be fixed promptly.
PackageReleaseNotes property instead of being appended to therc; both were promoted to stable during servicing and ship as 10.2.010.2.0-preview.1 alongside everything elseMicrosoft.OpenApi was updated to 2.7.5 due to a vulnerability and pinned to below 3.0.0 after a major versionThanks to everyone who contributed to this release, whether through code, issues, or test driving the changes.
Nothing published for this version
The official release for 10.0 is here! In addition to the changes in the preview releases, there are a few additional changes.
The official release for 10.0 is here! In addition to the changes in the preview releases, there are a few additional changes.
ApiVersionAttribute, MapToVersionAttribute, and AdvertiseApiVersionsAttribute all now have a constructor which can support the date format without being a string; for example, [ApiVersion(2026, 04, 01)]XmlCommentsTransformer is now resolved via DI, which allows it to be re-registered with a user-defined file pathvirtual for developer extensibilityIKeyedServiceProvider when injecting ApiVersion (#1178)"enum": ["1.0"] instead of "default": "1.0"
rc.1 because Microsoft.AspNetCore.OData is only at preview.2rc.1 pending the outcome of dotnet/aspnetcore#66408
Thanks to the contributors on this release whether it was code contributions or test driving the previews. Special thanks to @sander1095 for being a strong advocate and helping to bring even more visibility to the project.
This release is a quick iteration which contains minor fixes based on feedback from Preview 1.
Trying out previews is always a big ask. The OpenAPI extensions are net new, so I really am looking for some community support to flush out any edge cases I may have been missed before releasing officially. All other libraries are stable.
Aside from whatever the community may report, there are only two final things I'm considering for the final release:
If these are not able to be completed within the next few weeks, then I will officially release the stable libraries. The gRPC support will then come in a future, likely minor version, release. The OpenAPI extensions may stay in preview as AOT will likely be broken.
_ prefix character when extracting API versions from a .NET namespace (#1172)<example> tags (#1170)The OpenAPI extensions for API Versioning (e.g. x-api-versioning) will now use a nested links property rather than a simple array. This allows the schema to be open for possible future enhancements.
Preview 1
{
"x-api-versioning":
[
{
"title": "Version Policy",
"type": "text/html",
"rel": "info",
"url": "http://my.api.com/policies/versioning.html"
}
]
}Preview 2+
{
"x-api-versioning":
{
"links":
[
{
"title": "Version Policy",
"type": "text/html",
"rel": "info",
"url": "http://my.api.com/policies/versioning.html"
}
]
}
}_ (#1172)This is a major release that includes new, publicly visible API changes as well as a rollup of bug fixes. This is an initial preview release that is primarily focused on improving OpenAPI integration. Additional features will come in the next preview. The wiki has not be fully updated - yet, but that will also occur in the near future.
These are preview features and changes. Please report issues if you find them. Feel free to start a discussion about the changes in the forthcoming official release.
x-api-versioning extensionHttpClient can now read and report on sunset and deprecation policiesThe following provides an example of a bare minimum setup:
var builder = WebApplication.CreateBuilder( args );
var services = builder.Services;
services.AddApiVersioning()
.AddApiExplorer()
.AddOpenApi();
var app = builder.Build();
var hello = app.NewVersionedApi( "HelloWorld" );
var v1 = hello.MapGroup( "/hello-world" ).HasApiVersion( 1.0 );
var v2 = hello.MapGroup( "/hello-world" ).HasApiVersion( 2.0 );
v1.MapGet( "/", ( ApiVersion version ) => $"Hello world from v{version}" );
v2.MapGet( "/", ( ApiVersion version ) => $"Hello world from v{version}" );
if ( app.Environment.IsDevelopment() )
{
app.MapOpenApi().WithDocumentPerVersion();
}
app.Run();The key differences from what you may be currently doing:
services.AddOpenApi( "v1" ) and so on are no longer used or neededapp.MapOpenApi() has a supplemental .WithDocumentPerVersion() extension that enables multiple OpenAPI documentsIn the same way that you can configure sunset policies, you can now specify deprecation policies:
services.AddApiVersioning()
.AddApiExplorer( options =>
{
options.Policies.Deprecate( 0.9 )
.Effective( DateTimeOffset.Now )
.Link( "policy.html" )
.Title( "Deprecation Policy" )
.Type( "text/html" );
})
.AddOpenApi();Description property when cloning (#1160)Breaking changes are always something to be taken seriously and should occur as infrequently as possible. When they do occur, they should occur at a clear, major version boundary. Breaking changes in the project will align to the .NET platform Long-Term Support (LTS) strategy. .NET 10 is a LTS version so now is the version to introduce these changes.
.NET 10 and C# 14 introduce extension members, which finally affords defining API Versioning extensions the way they were intended. More specifically, there are a number of extension properties that could not be written as such in the past. Extension properties enable more succinct code and express the intent where an extension method was the only option in the past. These make up the majority of the breaking changes, but unless you are an API Versioning extender or perform deep customization, you'll likely not notice any changes.
The introduction of deprecation polices highlighted the opportunity to genericize policy management and there is no longer a need for the sunset policy specific implementations. The function names and signatures remain the same, but the following types have been replaced:
ISunsetPolicyManager → IPolicyManager<SunsetPolicy>ISunsetPolicyBuilderExtensions → IPolicyBuilderExtensionsISunsetPolicyManagerExtensions → IPolicyManagerExtensionsThe following extension methods are now extension properties.
HttpRequestMessage
GetApiVersioningOptions() → ApiVersioningOptions { get; }GetApiVersioningProperties() → ApiVersioningProperties { get; }GetRequestedApiVersion() → RequestedApiVersion { get; }HttpActionDescriptor
GetApiVersionMetadata(), SetApiVersionMetadata() → ApiVersionMetadata { get; set; }HttpConfiguration
GetApiVersioningOptions() → ApiVersioningOptions { get; }HttpControllerDescriptor
GetApiVersionModel(), SetApiVersionModel() → ApiVersionModel { get; set; }The following extension methods are now extension properties.
ApiDescription
GetApiVersion() → ApiVersion { get; }IsDeprecated() → IsDeprecated { get; }GetGroupName() → GroupName { get; }GetUniqueID() → UniqueID { get; }The following extension methods are now extension properties.
IEdmModel
GetApiVersion() → ApiVersion { get; }IsAdHoc() → IsAdHoc { get; }The following extension methods are now extension properties.
ApiDescription
EdmModel() → EdmModel { get; }EntitySet() → EntitySet { get; }EntityType() → EntityType { get; }Operation() → Operation { get; }RoutePrefix() → RoutePrefix { get; }The following extension methods are now extension properties.
HttpContext
ApiVersioningFeature() → ApiVersioningFeature { get; }GetRequestedApiVersion() → RequestedApiVersion { get; }The following types and members have been removed:
DefaultApiVersionGroupDescriptionProvider, which was internally identical to GroupedApiVersionDescriptionProviderpublic EndpointApiVersionMetadataCollationProvider( EndpointDataSource endpointDataSource )IServiceCollectionExtensions.EnableApiVersionBinding; it's now supported without explicit registrationThe following extension methods are now extension properties.
ActionDescriptor
GetApiVersionMetadata() → ApiVersionMetadata { get; }ControllerModel
GetApiVersionModel() → ApiVersionModel { get; }The following extension methods are now extension properties.
ApiDescription
GetApiVersion(), SetApiVersion() → ApiVersion { get; set; }IsDeprecated() → IsDeprecated { get; }GetSunsetPolicy(), SetSunsetPolicy() → SunsetPolicy { get; set; }The following extension methods are now extension properties.
IEdmModel
GetApiVersion() → ApiVersion { get; }IsAdHoc() → IsAdHoc { get; }The following extension methods are now extension properties.
HttpResponseMessage
ReadSunsetPolicy() → SunsetPolicy { get; }deprecation header support (#1151)Nothing published for this version
This is a minor release that includes a new, publicly visible API changes as well as a rollup of bug fixes.
This is a minor release that includes a new, publicly visible API changes as well as a rollup of bug fixes.
IEndpointInspector (#1066)
EndpointApiVersionMetadataCollationProvider has a new constructor that accepts IEndpointInspector
Obsolete and will be removed in a 9.0AddErrorObjects make integration with the legacy Error Objects format easier (related to #1072)
JsonOptions configuration will remain implicit as it is today, but 9.0 will remove it
AddErrorObjects extension methods versus mapping IProblemDetailsWriter explicitlyJsonSerializerContext is now accessible, if neededAddErrorObjects<TWriter> allows configuring an extended/customized ErrorObjectWriter typeIApiVersionDescriptionProviderFactory.Create() extension method
IApiVersionDescriptionProviderFactory in DI also now replaces IApiVersionDescriptionProviderIApiVersionDescriptionProvider can still be individually replaced if you really want toApiExplorerSettingsAttribute together with ApiVersionAttribute produces unexpected number of ApiVersionDescriptions (#1066)None
This is the official release for .NET 8. This release primarily includes internal performance improvements based on new .NET 8 features and a limited
This is the official release for .NET 8. This release primarily includes internal performance improvements based on new .NET 8 features and a limited set of new features.
Asp.Versioning.AbstractionsAsp.Versioning.HttpAsp.Versioning.Http.ClientIApiVersionSelector.SelectVersionAsync (#1009)
SelectVersionSelectVersion must still be implemented1 The .NET Framework and ASP.NET MVC Core do not currently support AOT
In addition to the rollup of fixes in 7.1.0, the following outlines the fixes in this release.
ControllerNameAttribute is properly honored (#1042)ErrorObjectWriter constructor now requires an IOptions<JsonOptions> parameter
ErrorObjectWriter, the changes are transparentThis release provides some minor updates and patches. This will be the final release before .NET 8, which is just around the corner.
This release provides some minor updates and patches. This will be the final release before .NET 8, which is just around the corner.
The following outlines all new features since 7.0, but some of them have already been released in a previous patch.
ApiVersioningOptions.DefaultApiVersion cannot be ApiVersion.Neutral (#1011)IApiVersionSelector to ApiExplorerOptions (#1025)
ApiVersioningOptions by defaultApiExplorerOptions.ApiVersionSelector while determining if the 1st API version parameter is required (#1025)EnableQueryAttribute to override Model Bound Settings (#928)EnableQueryAttribute to override Model Bound Settings (#928)This is a rollup of all fixes since 7.0, some of which were already released in patch.
ProblemDetails.Type$top in examples (#944)ApiVersioningOptions to ApiExplorerOptions$top in examples (#944)None
Nothing published for this version
This is a summary of all breaking changes from the first previews to the final release.
The official release for .NET 7.0 is finally here. There have been numerous changes between the previews and fixes that occurred in 6.0 so they will all be collated here for your convenience.
The primary feature and enhancement areas include:
var builder = WebApplication.CreateBuilder( args );
builder.Services.AddApiVersioning();
var app = builder.Build();
var orders = app.NewVersionedApi(); // ← group for an api with an optional name
var v1 = orders.MapGroup( "/api/order" ).HasApiVersion( 1.0 ); // ← all endpoints in this group have 1.0
var v2 = orders.MapGroup( "/api/order" ).HasApiVersion( 2.0 ); // ← all endpoints in this group have 2.0
v1.MapGet( "/{id:int}", ( int id ) => new V1.Order() { Id = id, Customer = "John Doe" } );
v2.MapGet( "/{id:int}", ( int id ) => new V2.Order() { Id = id, Customer = "John Doe", Phone = "555-555-5555" } );
v2.MapDelete( "/{id:int}", ( int id ) => Results.NoContent() );Several OData query settings, such as the allowed properties, can only be configured using Model Bound settings. This information is annotated in the Entity Data Model (EDM). How do you configure this information if you're only using some of OData and don't have an EDM?
The OData API Explorer extensions already support using conventions, but it does not allow you to specify a convention which cannot be mapped to some combination of ODataQueryOptionSettings or ODataValidationSettings. ModelBoundSettings is supported, but mapping custom conventions over it would largely be a duplication of what ODataModelBuilder already does.
The new API Explorer support bridges this gap by creating ad hoc EDM instances on your behalf for the sole purpose of configuring Model Bound settings. This allows you to define configurations you couldn't otherwise without having to use an EDM. You have the choice to use attributes or the ODataModelBuilder fluent API for conventions.
Consider the following:
[Filter( "author", "published" )] // ← model bound settings with attributes
public class Book
{
public string Id { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public int Published { get; set; }
}For ASP.NET Core, that's it; there is nothing else you need to do. ASP.NET Web API doesn't support DI out-of-the-box, so you'll need the following basic setup:
configuration.AddODataApiExplorer(
options => options.AdHocModelBuilder
.ModelConfigurations
.Add( new ImplicitModelBoundSettingsConvention() ) );Both platforms support adding, removing, or using conventions. The result of this configuration will show the $filter query option and indicate only the author and published properties can be used. If you prefer not to use attributes, the convention-based API can be used as well:
AddODataApiExplorer(
options =>
options.AdHocModelBuilder.DefaultConfiguration = (builder, version, prefix) =>
builder.ComplexType<Book>().Filter( "author", "published" ) ) ;The ad hoc EDM is only available during API exploration and is then discarded. It does not opt into any OData features.
ApiVersioningOptions.UnsupportedApiVersionStatusCode allows specifying a custom HTTP status code
400404 will always be usedODataApiExplorerOptions.AdHocModelBuilder to add or configure conventionsIProblemDetailsFactory to IProblemDetailsRouteGroupBuilder)ApiVersionSetBuilderFactory as an injectable delegateVersionedEndpointRouteBuilderFactory as an injectable delegateApiVersioningOptions.UnsupportedApiVersionStatusCode allows specifying a custom HTTP status code
400404 will always be usedIApiVersionMetadataCollationProvider serviceODataApiExplorerOptions.AdHocModelBuilder which is used in the same way as ODataApiVersioningOptions.ModelBuilderStackOverflowException in AdvertiseApiVersionsAttribute (#932)404 over 400 when versioning only by URL segment (#911)IApiVersioningBuilder.AddMvc ensures dependent services are registeredIApiVersioningBuilder.AddApiExplorer ensures dependent services are registeredCode extension in ProblemDetails is correctly written in JSON as codeNewVersionedApi when used WithOpenApi (#920)This is a summary of all breaking changes from the first previews to the final release.
DefaultApiVersionReporter constructor added ISunsetPolicyManagerProblemDetails implementation
IProblemDetailsFactory has been removed and is supplanted by the built-in IProblemDetailsServiceAddProblemDetails() must be called to add ProblemDetails, which may result in a behavioral changeMapApiGroup is now NewVersionedApi (ASP.NET team recommendation)IVersionedEndpointConventionBuilder has been removedVersionedEndpointConventionBuilder has been removedDefaultApiVersionSetBuilderFactory has been replaced by the ApiVersionSetBuilderFactory delegateIVersionedEndpointConventionBuilder.WithApiVersionSet now has the signature TBuilder WithApiVersionSet<TBuilder>(TBuilder, ApiVersionSet) where TBuilder : notnull, IEndpointConventionBuilderIEnumerable<IApiVersionMetadataCollationProvider>:
ApiVersionMatcherPolicyDefaultApiVersionDescriptionProviderGroupedApiVersionDescriptionProviderDefaultApiVersionReporter constructor added ISunsetPolicyManagerApiExplorerOptionsFactory<T> was changed to:
OptionsFactory<T>Setups propertyPostConfigures propertyThanks you to all that contributed directly with code, filing issues, and in-depth discussions. In particular, special thanks to:
The release candidate for .NET 7.0 is finally here. Barring any reported bugs, this should be the release. Big thanks to the early adopters that have tried things out and reported issues.
This release also contains fixes that were forward-integrated from
6.3and6.3.1.
MapApiGroup when used WithOpenApi (#920)AddProblemDetails in example projects (now required to retain default ProblemDetails behavior; new in .NET 7)There weren't any expected breaking changes, but there are some. #922 revealed that API versions were not collated as expected when building the route tree. Collation is split between Minimal APIs and traditional controllers. It is possible to have both. Previously, EndpointDataSource and IActionDescriptorCollectionProvider would have been supplied via DI. Since the ApiVersionMatcherPolicy now only depends on Microsoft.AspNetCore.Routing this was a problem.
6.3.1 subtly introduced IApiVersionMetadataCollationProvider which provides an adapter of sorts over EndpointDataSource and IActionDescriptorCollectionProvider respectively, but allows them to be independently added to DI as you add those features in. This ultimately requires changing the constructor signature of a few types:
ApiVersionMatcherPolicyDefaultApiVersionDescriptionProviderGroupedApiVersionDescriptionProviderto add or replace their parameters with IEnumerable<IApiVersionMetadataCollationProvider>. In 6.3.1, some DI trickery was done with internal constructors to prevent breaking changes to the existing public surface area (though all the necessary extension pieces are public). Since 7.0 is still in preview, now is the time to apply this change.
Unless you are doing a lot of low-level customization or extensions, you probably won't notice these changes.
This is a backport of the OData API Explorer extensions for ad hoc EDM intended for .NET 6.0 and .NET Core 3.1. Most people should move on to 7.0 .
This is a backport of the OData API Explorer extensions for ad hoc EDM intended for .NET 6.0 and .NET Core 3.1. Most people should move on to 7.0.
ODataApiExplorerOptions.AdHocModelBuilder which is used in the same way as ODataApiVersioningOptions.ModelBuilderSeveral OData query settings, such as the allowed properties, can only be configured using Model Bound settings. This information is annotated in the Entity Data Model (EDM). How do you configure this information if you're only using some of OData and don't have an EDM?
The OData API Explorer extensions already support using conventions, but it does not allow you to specify a convention which cannot be mapped to some combination of ODataQueryOptionSettings or ODataValidationSettings. ModelBoundSettings is supported, but mapping custom conventions over it would largely be a duplication of what ODataModelBuilder already does.
The new API Explorer support bridges this gap by creating ad hoc EDM instances on your behalf for the sole purpose of configuring Model Bound settings. This allows you to define configurations you couldn't otherwise without having to use an EDM. You have the choice to use attributes or the ODataModelBuilder fluent API for conventions.
Consider the following:
[Filter( "author", "published" )] // ← model bound settings with attributes
public class Book
{
public string Id { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public int Published { get; set; }
}The result of this configuration will show the $filter query option and indicate only the author and published properties can be used. If you prefer not to use attributes, the convention-based API can be used as well:
AddODataApiExplorer(
options =>
options.AdHocModelBuilder.DefaultConfiguration = (builder, version, prefix) =>
builder.ComplexType<Book>().Filter( "author", "published" ) ) ;The ad hoc EDM is only available during API exploration and is then discarded. It does not opt into any OData features.
None
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →