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.
Features
All Platforms
ASP.NET Core
- Integration with the Microsoft.AspNetCore.OpenApi library
- These features in the new Asp.Versioning.OpenApi library
- OpenAPI documents are now generated per API version
- Sunset and deprecation policies are automatically included with standard (English) text, but can be customized
- Sunset and deprecation policies links are included in OpenAPI documents via the
x-api-versioningextension - The versioned
HttpClientcan now read and report on sunset and deprecation policies - All example projects have been updated to use Scalar
Example
The 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:
- The calls to
services.AddOpenApi( "v1" )and so on are no longer used or needed app.MapOpenApi()has a supplemental.WithDocumentPerVersion()extension that enables multiple OpenAPI documents
In 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();Fixes
ASP.NET Core
API Explorer
- Include
Descriptionproperty when cloning (#1160)
Breaking Changes
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.
All Platforms
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→IPolicyManagerExtensions
ASP.NET Web API
The following extension methods are now extension properties.
HttpRequestMessageGetApiVersioningOptions()→ApiVersioningOptions { get; }GetApiVersioningProperties()→ApiVersioningProperties { get; }GetRequestedApiVersion()→RequestedApiVersion { get; }
HttpActionDescriptorGetApiVersionMetadata(),SetApiVersionMetadata()→ApiVersionMetadata { get; set; }
HttpConfigurationGetApiVersioningOptions()→ApiVersioningOptions { get; }
HttpControllerDescriptorGetApiVersionModel(),SetApiVersionModel()→ApiVersionModel { get; set; }
API Explorer
The following extension methods are now extension properties.
ApiDescriptionGetApiVersion()→ApiVersion { get; }IsDeprecated()→IsDeprecated { get; }GetGroupName()→GroupName { get; }GetUniqueID()→UniqueID { get; }
OData
The following extension methods are now extension properties.
IEdmModelGetApiVersion()→ApiVersion { get; }IsAdHoc()→IsAdHoc { get; }
OData API Explorer
The following extension methods are now extension properties.
ApiDescriptionEdmModel()→EdmModel { get; }EntitySet()→EntitySet { get; }EntityType()→EntityType { get; }Operation()→Operation { get; }RoutePrefix()→RoutePrefix { get; }
ASP.NET Core
The following extension methods are now extension properties.
HttpContextApiVersioningFeature()→ApiVersioningFeature { get; }GetRequestedApiVersion()→RequestedApiVersion { get; }
MVC (Core)
The following types and members have been removed:
DefaultApiVersionGroupDescriptionProvider, which was internally identical toGroupedApiVersionDescriptionProvider- Obsolete constructor
public EndpointApiVersionMetadataCollationProvider( EndpointDataSource endpointDataSource ) - Removed
IServiceCollectionExtensions.EnableApiVersionBinding; it's now supported without explicit registration
The following extension methods are now extension properties.
ActionDescriptorGetApiVersionMetadata()→ApiVersionMetadata { get; }
ControllerModelGetApiVersionModel()→ApiVersionModel { get; }
API Explorer
The following extension methods are now extension properties.
ApiDescriptionGetApiVersion(),SetApiVersion()→ApiVersion { get; set; }IsDeprecated()→IsDeprecated { get; }GetSunsetPolicy(),SetSunsetPolicy()→SunsetPolicy { get; set; }
OData
The following extension methods are now extension properties.
IEdmModelGetApiVersion()→ApiVersion { get; }IsAdHoc()→IsAdHoc { get; }
Versioned HTTP Client
The following extension methods are now extension properties.
HttpResponseMessageReadSunsetPolicy()→SunsetPolicy { get; }
Contributors
- Huge thanks to @MGessinger who implemented most of the new
deprecationheader support (#1151)