Skip to content

Releases: dotnet/aspnet-api-versioning

8.1.0

26 Mar 17:42
Compare
Choose a tag to compare

This is a minor release that includes a new, publicly visible API changes as well as a rollup of bug fixes.

Features

ASP.NET Core

  • Added IEndpointInspector (#1066)
    • Enables controller action endpoints to not be processed by Minimal API endpoint collators
    • EndpointApiVersionMetadataCollationProvider has a new constructor that accepts IEndpointInspector
      • The previous constructor is now Obsolete and will be removed in a 9.0
  • Added AddErrorObjects make integration with the legacy Error Objects format easier (related to #1072)
    • The underlying JsonOptions configuration will remain implicit as it is today, but 9.0 will remove it
      • It is recommended you use one of the AddErrorObjects extension methods versus mapping IProblemDetailsWriter explicitly
    • The associated JsonSerializerContext is now accessible, if needed
    • AddErrorObjects<TWriter> allows configuring an extended/customized ErrorObjectWriter type
  • Added IApiVersionDescriptionProviderFactory.Create() extension method
    • Replacing IApiVersionDescriptionProviderFactory in DI also now replaces IApiVersionDescriptionProvider
    • IApiVersionDescriptionProvider can still be individually replaced if you really want to

Fixes

All Platforms

  • Correct sunset policy resolution when falling back (#1065)
  • Fails to read new versions when available (#1070)

ASP.NET Core

  • Using ApiExplorerSettingsAttribute together with ApiVersionAttribute produces unexpected number of ApiVersionDescriptions (#1066)

ASP.NET Core with OData

  • Support OData Collection Parameters (#999)

Breaking Changes

None

8.0.0

08 Dec 21:43
Compare
Choose a tag to compare

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.

Features

ASP.NET Core

  • AOT Compatibility1:
    • Asp.Versioning.Abstractions
    • Asp.Versioning.Http
    • Asp.Versioning.Http.Client
  • Added IApiVersionSelector.SelectVersionAsync (#1009)
    • The default interface implementation simply calls SelectVersion
    • SelectVersion must still be implemented
    • The synchronous path must be accounted for
    • Some use cases, such as with OData, does have synchronous code paths that cannot be refactored

1 The .NET Framework and ASP.NET MVC Core do not currently support AOT

Fixes

In addition to the rollup of fixes in 7.1.0, the following outlines the fixes in this release.

ASP.NET Core

  • ControllerNameAttribute is properly honored (#1042)

Breaking Changes

ASP.NET Core

  • The ErrorObjectWriter constructor now requires an IOptions<JsonOptions> parameter
    • If you don't use Error Object responses, this change has no effect
    • If you use Error Object responses, but you don't extend or customize the default ErrorObjectWriter, the changes are transparent

Contributors

  • Big thanks to @xavierjohn who:
    • Fixed #1042
    • Reviewed and researched AOT support
    • Reviewed and researched many of the .NET 8 update issues

7.1.0

09 Oct 19:44
Compare
Choose a tag to compare

This release provides some minor updates and patches. This will be the final release before .NET 8, which is just around the corner.

Features

The following outlines all new features since 7.0, but some of them have already been released in a previous patch.

All Platforms

  • Enable NuGet Symbol packages
  • Validate ApiVersioningOptions.DefaultApiVersion cannot be ApiVersion.Neutral (#1011)
  • Support Error Object backward compatibility (#1019)
  • Add IApiVersionSelector to ApiExplorerOptions (#1025)
    • Derives from ApiVersioningOptions by default
    • Can be overridden with a different instance just for documentation
  • Use ApiExplorerOptions.ApiVersionSelector while determining if the 1st API version parameter is required (#1025)

ASP.NET Web API with OData

  • Use complex types instead of entities for ad hoc models so a key is not required
  • Allow EnableQueryAttribute to override Model Bound Settings (#928)

ASP.NET Core with OData

  • Use complex types instead of entities for ad hoc models so a key is not required
  • Allow EnableQueryAttribute to override Model Bound Settings (#928)

Fixes

This is a rollup of all fixes since 7.0, some of which were already released in patch.

ASP.NET Web API

  • Fix JSON serialization of ProblemDetails.Type

ASP.NET Web API with OData

  • Fix empty model check, which didn't include complex types
  • Fix use of $top in examples (#944)
  • Fix models in multiple EDMs with the same API version (#996)

ASP.NET Core

  • Fix media type subset matching (#1015)
  • Prevent possible infinite recursion reading API versions when misconfigured (#1017)
  • Fix propagation of ApiVersioningOptions to ApiExplorerOptions
  • Explicit API description should supersede implicit match (#1025)

ASP.NET Core with OData

  • Fix empty model check, which didn't include complex types
  • Fix use of $top in examples (#944)
  • Fix models in multiple EDMs with the same API version (#996)

Breaking Changes

None

6.4.0

28 Dec 03:32
Compare
Choose a tag to compare

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.

Features

ASP.NET Core with OData

  • Added support for ad hoc Model Bound Settings
    • Add ODataApiExplorerOptions.AdHocModelBuilder which is used in the same way as ODataApiVersioningOptions.ModelBuilder
    • Examples:

Non-OData Model Bound Settings

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.

Fixes

ASP.NET Core with OData

  • Fixed empty EDM detection

Breaking Changes

None

Contributors

7.0.0

08 Dec 20:39
Compare
Choose a tag to compare

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.

Features

The primary feature and enhancement areas include:

  • Support for .NET 7.0
  • Enhanced support for Minimal APIs with grouping
  • Expanded support for exploring OData query options in non-OData APIs

Minimal APIs

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() );

Non-OData Model Bound Settings

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.

ASP.NET Web API

  • ApiVersioningOptions.UnsupportedApiVersionStatusCode allows specifying a custom HTTP status code
    • The default value is 400
    • This property is ignored when versioning by URL segment and 404 will always be used
  • A Sunset Policy will always attempt be written when reporting API versions

ASP.NET Web API with OData

  • Added support for ad hoc Model Bound Settings
    • Add ODataApiExplorerOptions.AdHocModelBuilder to add or configure conventions
    • Examples:

ASP.NET Core

  • Migration from IProblemDetailsFactory to IProblemDetails
  • Minimal APIs:
    • Add group support
    • Support adding metadata to groups (e.g. RouteGroupBuilder)
    • Add ApiVersionSetBuilderFactory as an injectable delegate
    • Add VersionedEndpointRouteBuilderFactory as an injectable delegate
    • Examples:
  • ApiVersioningOptions.UnsupportedApiVersionStatusCode allows specifying a custom HTTP status code
    • The default value is 400
    • This property is ignored when versioning by URL segment and 404 will always be used
  • A Sunset Policy will always attempt be written when reporting API versions
  • Added the IApiVersionMetadataCollationProvider service

ASP.NET Core with OData

  • Added support for ad hoc Model Bound Settings
    • Add ODataApiExplorerOptions.AdHocModelBuilder which is used in the same way as ODataApiVersioningOptions.ModelBuilder
    • Examples:

Fixes

All Platforms

  • Fix StackOverflowException in AdvertiseApiVersionsAttribute (#932)

ASP.NET Core

  • Use 404 over 400 when versioning only by URL segment (#911)
  • Do not explore unversioned endpoint more than once (#917)
  • IApiVersioningBuilder.AddMvc ensures dependent services are registered
  • IApiVersioningBuilder.AddApiExplorer ensures dependent services are registered
  • The Code extension in ProblemDetails is correctly written in JSON as code
  • API versions are reported when an endpoint is unmatched (#876, #918)
    • This is best effort, but restore behavior for unmatched endpoints prior to 6.0
  • Honor the name provided in NewVersionedApi when used WithOpenApi (#920)
  • Refactor API version metadata collation (#922)
  • Fix regression from custom group names (#923)

ASP.NET Core with OData

  • Provide workaround for OData/AspNetCoreOData/#753

Breaking Changes

This is a summary of all breaking changes from the first previews to the final release.

ASP.NET Web API

  • DefaultApiVersionReporter constructor added ISunsetPolicyManager

ASP.NET Core

  • As previously announced, .NET Core 3.1 has been dropped and is end of life
  • 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 change
  • Minimal APIs:
    • Since RC 1:
      • MapApiGroup is now NewVersionedApi (ASP.NET team recommendation)
    • Since 6.0:
      • IVersionedEndpointConventionBuilder has been removed
      • VersionedEndpointConventionBuilder has been removed
      • DefaultApiVersionSetBuilderFactory has been replaced by the ApiVersionSetBuilderFactory delegate
      • IVersionedEndpointConventionBuilder.WithApiVersionSet now has the signature TBuilder WithApiVersionSet<TBuilder>(TBuilder, ApiVersionSet) where TBuilder : notnull, IEndpointConventionBuilder
  • The following constructors were updated with IEnumerable<IApiVersionMetadataCollationProvider>:
    • ApiVersionMatcherPolicy
    • DefaultApiVersionDescriptionProvider
    • GroupedApiVersionDescriptionProvider
  • DefaultApiVersionReporter constructor added ISunsetPolicyManager
  • ApiExplorerOptionsFactory<T> was changed to:
    • Inherit from OptionsFactory<T>
    • Remove Setups property
    • Remove PostConfigures property

Contributors

Thanks you to all that contributed directly with code, filing issues, and in-depth discussions. In particular, special thanks to:

7.0.0 RC 1

26 Nov 23:33
Compare
Choose a tag to compare
7.0.0 RC 1 Pre-release
Pre-release

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 and 6.3.1.

Fixes

ASP.NET Core

  • Honor the name provided in MapApiGroup when used WithOpenApi (#920)
  • Refactor API version metadata collation (#922)
  • Fix regression from custom group names (#923)
  • AddProblemDetails in example projects (now required to retain default ProblemDetails behavior; new in .NET 7)

ASP.NET Core with OData

  • Provide workaround for OData/ODataAspNetCore#753

Breaking Changes

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.

6.3.0

19 Nov 20:11
Compare
Choose a tag to compare

This is a minor update, which includes some routing improvements.

Features

All Platforms

  • ApiVersioningOptions.UnsupportedApiVersionStatusCode has been added to indicate the status code used when an API version doesn't match
    • The default value is 400, which has been the de facto from the beginning
    • Any status code can be used, but 400, 404, or 501 are generally the ones that make sense
    • Each response will continue to include ProblemDetails, which is always the same; regardless of status code
    • When versioning exclusively by URL segment or the incoming request URL is determined to yield an API version route parameter, this option is ignored and the response will always be 404
  • A Sunset Policy will always attempt be written when reporting API versions
    • Previously, it was only written on success because success is required for API-specific policies
    • A version-specific policy can be written even during failure since it is related to the version as a whole, regardless of API

Fixes

ASP.NET Core

  • 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
  • The ProblemDetails.Code extension is now correctly written in JSON as code
  • API versions are now reported when an endpoint is unmatched (#876, #918)
    • This should restore the behavior for unmatched endpoints that existed prior to 6.0
    • This is a best effort
      • No erroneous scenarios have been found, but there could be edge cases
      • The behavior is relying on the routing system to collate the metadata from endpoints that are already collated by name using their route templates
      • Attempts to create contrived configurations that could yield incorrect results were unsuccessful (which is good)

Breaking Changes

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:

ASP.NET Web API

(ApiVersioningOptions options) => options.UnsupportedApiVersionStatusCode = HttpStatusCode.NotFound

ASP.NET Core

(ApiVersioningOptions options) => options.UnsupportedApiVersionStatusCode = 404

Special note for .NET Core 3.1 users. There are edge cases where 404 is returned instead of 400. 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.

7.0.0 Preview 2

17 Nov 04:47
Compare
Choose a tag to compare
7.0.0 Preview 2 Pre-release
Pre-release

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.

Features

ASP.NET Core

  • Added MapApiGroup() as a shortcut for MapGroup( "" ).WithApiVersionSet()
  • Metadata can now be added to groups (e.g. RouteGroupBuilder)
  • Added injectable VersionedEndpointRouteBuilderFactory delegate

In 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:

Fixes

  • Use 404 over 400 when versioning only by URL segment (#911)

Breaking Changes

The following are breaking changes from Preview 1. If you haven't added any customizations, these should all be source code compatible.

  • Add group metadata validation to avoid common developer mistakes
  • Replace IApiVersionSetBuilderFactory interface with injectable ApiVersionSetBuilderFactory delegate
  • Refactor RouteHandlerBuidler extensions into IEndpointRouteBuilderExtensions
    • This allows adding metadata on an endpoint or route group

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.

7.0.0 Preview 1

14 Nov 15:47
Compare
Choose a tag to compare
7.0.0 Preview 1 Pre-release
Pre-release

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.

Features

ASP.NET Core

  • Migrate from IProblemDetailsFactory to IProblemDetails
  • Adding grouping support for 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 );

ASP.NET Core with OData

  • OData does not officially support .NET 7, but it is compatible
    • It is assumed that the eventual support will continue to be forward compatible or bump to 9.0
    • A breaking change in 9.0 could cause complication or require a major version bump for OData packages here

Breaking Changes

  • As previously announced, .NET Core 3.1 has been dropped and is end of life in December 2022
  • Minimal APIs implementation:
    • IVersionedEndpointConventionBuilder and VersionedEndpointConventionBuilder have been removed and are no longer necessary
    • DefaultApiVersionSetBuilderFactory now has a parameterless, default constructor
    • IVersionedEndpointConventionBuilder 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
    • The built-in IServiceCollection.AddProblemDetails() must be called to add ProblemDetails
      • This puts the control in your hands
      • Can result in a behavioral breaking change if you omit the setup

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.

6.2.0

08 Nov 04:03
Compare
Choose a tag to compare

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.

Features

Abstractions

  • Added ApiVersionMetadata copy constructor

All Platforms

  • Add complex media type API version reader support (#887)

ASP.NET Web API

  • Type-forward route parsing from API Explorer to core library

ASP.NET Web API with OData

  • Add support for exploring OData metadata routes (#893)

ASP.NET Core

  • Support 406 and 415 with ProblemDetails (#886)
  • Handle missing ApiVersionMetadata (#891)
  • Handle multiple SelectorModel instances (#896)
  • Add IApiVersionDescriptionProviderFactory (enables DI within DescribeApiVersions)
  • Add support for custom group name formatting

ASP.NET Core with OData

  • Add support for exploring OData metadata routes (#893)

New Feature Preview

Enhanced Media Type Reader

The new MediaTypeApiVersionReaderBuilder has compositional support with the following features:

  • Multiple parameters (if they vary by media type)
  • Including specific media types
  • Excluding specific media types
  • Matching a version in a media type by regular expression (it's an escape hatch really)
  • Matching a version in a media type by a template
  • Disambiguate from multiple choices

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:

  • A parameter named v on any media type filtered to:
    • application/json
    • application/xml
  • A media type matching the template application/vnd-v{ver}+json where ver is the user-defined parameter name
  • A media type matching the template application/vnd-v{ver}+xml where ver is the user-defined parameter name

Composite 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 name
  • If a group name is defined and ApiExplorerOptions.FormatGroupName is null, the group name is used
  • If a group name is defined and ApiExplorerOptions.FormatGroupName is not null, the callback is invoked with the group name and formatted API version
  • If a group name is not defined, then the formatted API version is used

In 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 );

Breaking Changes

No known breaking changes

Contributors

Thanks you to all that contributed directly with code, filling issues, and in-depth discussions. In particular, special thanks to: