Provides a set of libraries which add service API versioning to ASP.NET Web API, OData with ASP.NET Web API, and ASP.NET Core.
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.0
AddErrorObjects
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 IApiVersionDescriptionProvider
IApiVersionDescriptionProvider
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 set of new features.
Asp.Versioning.Abstractions
Asp.Versioning.Http
Asp.Versioning.Http.Client
IApiVersionSelector.SelectVersionAsync
(#1009)
SelectVersion
SelectVersion
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.
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
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.ModelBuilder
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; }
}
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
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
400
404
will always be usedODataApiExplorerOptions.AdHocModelBuilder
to add or configure conventionsIProblemDetailsFactory
to IProblemDetails
RouteGroupBuilder
)ApiVersionSetBuilderFactory
as an injectable delegateVersionedEndpointRouteBuilderFactory
as an injectable delegateApiVersioningOptions.UnsupportedApiVersionStatusCode
allows specifying a custom HTTP status code
400
404
will always be usedIApiVersionMetadataCollationProvider
serviceODataApiExplorerOptions.AdHocModelBuilder
which is used in the same way as ODataApiVersioningOptions.ModelBuilder
StackOverflowException
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 code
NewVersionedApi
when used WithOpenApi
(#920)This is a summary of all breaking changes from the first previews to the final release.
DefaultApiVersionReporter
constructor added ISunsetPolicyManager
ProblemDetails
implementation
IProblemDetailsFactory
has been removed and is supplanted by the built-in IProblemDetailsService
AddProblemDetails()
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, IEndpointConventionBuilder
IEnumerable<IApiVersionMetadataCollationProvider>
:
ApiVersionMatcherPolicy
DefaultApiVersionDescriptionProvider
GroupedApiVersionDescriptionProvider
DefaultApiVersionReporter
constructor added ISunsetPolicyManager
ApiExplorerOptionsFactory<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.3
and6.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:
ApiVersionMatcherPolicy
DefaultApiVersionDescriptionProvider
GroupedApiVersionDescriptionProvider
to 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 minor update, which includes some routing improvements.
ApiVersioningOptions.UnsupportedApiVersionStatusCode
has been added to indicate the status code used when an API version doesn't match
400
, which has been the de facto from the beginning400
, 404
, or 501
are generally the ones that make senseProblemDetails
, which is always the same; regardless of status code404
IApiVersioningBuilder.AddMvc
and IApiVersioningBuilder.AddApiExplorer
now ensure dependent services are registered
AddApiExplorer
, in particular, snagged a number of people that didn't realize they needed AddMvc
ProblemDetails.Code
extension is now correctly written in JSON as code
6.0
Restoring the unmatched endpoint behavior may break the expectations for those that have adopted 6.0
. There's no good answer or time for this change to occur since this is an implementation detail that only manifests in behavior. Despite calling out the changes in the roadmap and release notes, several issues have been filed related to the change in 6.0
. At the time, it didn't seem possible to retain that functionality, but it seems that - largely - it can be.
Ultimately, this change only affects APIs that are strictly concerned about whether the response will be 400
or 404
for client errors on unmatched versions. 400
will now revert to be the default case where you might have received 404
. If it's important to you to retain the behaviors you've established while adopting 6.x
, you can achieve that by setting:
(ApiVersioningOptions options) => options.UnsupportedApiVersionStatusCode = HttpStatusCode.NotFound
(ApiVersioningOptions options) => options.UnsupportedApiVersionStatusCode = 404
Special note for .NET Core 3.1 users. There are edge cases where
404
is returned instead of400
. In reviewing the test cases, this was already a problem. It's unclear why that happens, but it appears to be a change or fix in the routing system in at least .NET 6.0 and above. This will be considered the expected behavior. It may be possible to change the behavior with middleware.
This is the second and likely final preview release for ASP.NET Core with .NET 7.0 support. No additional work is planned, but there are some breaking changes that can be tried, tested, and discussed before promoting to the official release.
MapApiGroup()
as a shortcut for MapGroup( "" ).WithApiVersionSet()
RouteGroupBuilder
)VersionedEndpointRouteBuilderFactory
delegateIn Preview 2, metadata can now be applied even more succinctly.
var builder = WebApplication.CreateBuilder( args );
builder.Services.AddApiVersioning();
var app = builder.Build();
var orders = app.MapApiGroup(); // ← api group with 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() );
All of the previous methods of configuring metadata are still supported. For more examples, refer to the:
404
over 400
when versioning only by URL segment (#911)The following are breaking changes from Preview 1. If you haven't added any customizations, these should all be source code compatible.
IApiVersionSetBuilderFactory
interface with injectable ApiVersionSetBuilderFactory
delegateRouteHandlerBuidler
extensions into IEndpointRouteBuilderExtensions
If you have additional input or feedback, please provide them in the discussion. This will likely be the last time to discuss it before the release becomes official.
This is the first preview release for ASP.NET Core with .NET 7.0 support. No additional work is planned, but there are some breaking changes that can be tried, tested, and discussed before promoting to the official release.
IProblemDetailsFactory
to IProblemDetails
MapGroup
in Minimal APIs
Versioning Minimal APIs still requires a version set which collates configured API versions, but the new MapGroup
support makes the setup more natural.
var builder = WebApplication.CreateBuilder( args );
builder.Services.AddApiVersioning();
var app = builder.Build();
var orders = app.MapGroup( "/api/order" ).WithApiVersionSet();
orders.MapGet( "/{id:int}", ( int id ) => new Order() { Id = id, Customer = "John Doe" } ).HasApiVersion( 1.0 );
9.0
9.0
could cause complication or require a major version bump for OData packages hereIVersionedEndpointConventionBuilder
and VersionedEndpointConventionBuilder
have been removed and are no longer necessaryDefaultApiVersionSetBuilderFactory
now has a parameterless, default constructorIVersionedEndpointConventionBuilder WithApiVersionSet(IEndpointConventionBuilder, ApiVersionSet)
is now TBuilder WithApiVersionSet<TBuilder>(TBuilder, ApiVersionSet) where TBuilder : notnull, IEndpointConventionBuilder
ProblemDetails
implementation
IProblemDetailsFactory
has been removed and is supplanted by the built-in IProblemDetailsService
IServiceCollection.AddProblemDetails()
must be called to add ProblemDetails
If you have additional input or feedback, please provide them in the discussion. This will be the one and only time to discuss it before the release becomes official.
This is a minor release which contains mostly fixes and a few new enhancements. The next phase in the roadmap will be supporting .NET 7.0.
.NET Core 3.1 will be End of Life in December of 2022; therefore, support for that target framework will be dropped in the next major release. With the exception of servicing for bug fixes, this will be the last release for .NET Core 3.1.
ApiVersionMetadata
copy constructor406
and 415
with ProblemDetails
(#886)ApiVersionMetadata
(#891)SelectorModel
instances (#896)IApiVersionDescriptionProviderFactory
(enables DI within DescribeApiVersions
)Enhanced Media Type Reader
The new MediaTypeApiVersionReaderBuilder
has compositional support with the following features:
Here's a basic example:
var builder = new MediaTypeApiVersionReaderBuilder()
var reader = builder
.Parameter( "v" )
.Include( "application/json" )
.Include( "application/xml" )
.Template( "application/vnd-v{ver}+json" )
.Template( "application/vnd-v{ver}+xml" )
.Build();
This will match:
v
on any media type filtered to:
application/json
application/xml
application/vnd-v{ver}+json
where ver
is the user-defined parameter nameapplication/vnd-v{ver}+xml
where ver
is the user-defined parameter nameComposite Group Names
The API Explorer and OpenAPI (aka Swagger) UI do not support multi-level grouping. Implementing some form of this has been possible, but complex in the past. API Versioning uses a formatted API version as the group name as a logical choice, but some people want to combine that with a group name. A new feature will give you the option to format a group name and API version together.
services.AddApiVersioning()
.AddApiExplorer( options =>
{
options.GroupNameFormat = "'v'VVV";
options.FormatGroupName = (groupName, apiVersion) => $"{groupName}-{apiVersion}";
});
There are multiple ways to define a group name, but a controller might look like:
[ApiVersion( 1.0 )]
[ApiController]
[ApiExplorerSettings( GroupName = "Example" )]
[Route( "[controller]" )]
public class ExampleController : ControllerBase
{
[HttpGet]
public IActionResult Get() => Ok();
}
The formatting rules are as follows:
ApiVersion.ToString( ApiExplorerOptions.GroupNameFormat )
is the default group nameApiExplorerOptions.FormatGroupName
is null
, the group name is usedApiExplorerOptions.FormatGroupName
is not null
, the callback is invoked with the group name and formatted API versionIn the example above, the final group name will become Example-v1
.
OData Metadata Endpoints
OData has a built-in Service Document and Metadata endpoint. These largely serve the same purpose as OpenAPI (aka Swagger) in days gone by. You might, however, still want these to show up. The default will continue to keep them hidden, but you can now enable showing one or both of them via:
services.AddControllers().AddOData();
services.AddApiVersioning()
.AddOData( options => options.AddRouteComponents() )
.AddODataApiExplorer( options.MetadataOptions = ODataMetadataOptions.All );
No known breaking changes
Thanks you to all that contributed directly with code, filling issues, and in-depth discussions. In particular, special thanks to: