Skip to content

Releases: dotnet/aspnet-api-versioning

10.2.0

Choose a tag to compare

@commonsensesoftware commonsensesoftware released this 06 Aug 04:51

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.

Fixes

All Platforms

  • Parsing an API version whose status ends in '.' no longer succeeds silently
  • Very large padding values in a format string no longer cause a stack overflow
  • Incorrect lower and upper bounds when matching API version ranges
  • Parsing a positive integer no longer allows whitespace or a leading '-'

ASP.NET Core

  • Routes are no longer incorrectly evicted from the route table (#1138)
  • Fixed routing of unversioned endpoints
  • Fixed extracting an API version that includes a status when versioning by URL segment (#1187)
  • A user-registered IProblemDetailsWriter is preserved by AddApiVersioning() (#1191)

ASP.NET Core OpenAPI

  • Support for more XML comment tags (#1205)
  • Fixed the error message reported for an unmapped JSON property
  • Fixed descriptions applied to filtered members

Features

All Platforms

  • New ApiVersionRange type for matching a set of API versions using the same interval notation as a package version
    • 1.0x ≥ 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.0
    • Multiple rules are combined as a logical or; ApiVersionRange.Any and ApiVersionRange.Empty are provided for
      the degenerate cases
    • A range matches API versions; it does not define them. API versions must still be explicitly declared
  • New VisibleInApiVersionAttribute indicates the range of API versions a data member is visible in; for example,
    [VisibleInApiVersion("2.0")]
  • New 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 recognized
    syntaxes are ApiVersion, ApiVersionRange, and ApiVersionFormat

Analyzers

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

  • Every rule has a helpLinkUri that resolves to its documentation page
  • Individual rules can be configured through .editorconfig as usual
  • All analyzers can be turned off with a single MSBuild property:
    <PropertyGroup>
      <EnableApiVersioningAnalyzers>false</EnableApiVersioningAnalyzers>
    </PropertyGroup>
    ExcludeAssets="analyzers" on a PackageReference will not work because the package is also reached through
    the dependencies of other packages and NuGet combines the assets from every path

ASP.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.

ASP.NET Core

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; }
}
  • Works for both Minimal APIs and MVC (Core)
  • Filtering members is currently only support for the JSON media type
  • Filtering applies on the way in as well as the way out, which closes the corresponding over-posting gap
  • AddApiVersioning() now registers IHttpContextAccessor so the requested API version is available during
    serialization
  • [VisibleInApiVersion] is part of the core abstractions and can be used in your model libraries without any
    dependency on ASP.NET

ASP.NET Core API Explorer

  • The API explorer describes only the model members visible in the API version being explored via the new
    VersionedModelMetadata, VersionedModelMetadataProvider, and DelegatingModelMetadata types
  • Only models that are actually explored are filtered for visibility

ASP.NET Core OpenAPI

  • Generated schemas reflect per-version member visibility, so the documented shape of a model matches what the API
    actually returns for that version
  • Significantly expanded XML comment support:
    • <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
    • Multi-line code fences from <code> blocks are properly closed

ASP.NET Core with gRPC (Preview)

Two 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 );
  • Services are versioned with the same conventions used everywhere else — a single implementation can support several
    API versions, or implementations can be split across versions
  • Message fields are annotated with the API versions they belong to using the new 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"];
    }
    • The option is repeated, so a field split across disjoint ranges repeats the option
    • A field with no annotation is included in every API version
  • A server interceptor filters fields out of requests and responses — including streaming in both directions — so a
    client on 1.0 can neither see nor post a field that was introduced in 3.0
  • JSON transcoded gRPC services are described by the API explorer and appear in the OpenAPI document with the API
    version route segment and well-known protobuf types mapped to their correct schemas

The gRPC OpenAPI Example demonstrates an end-to-end working solution.

Breaking Changes

All Platforms

  • The analyzers are on by default. They ship inside Asp.Versioning.Abstractions and Asp.Versioning.Http, which
    means upgrading turns them on for every project that references API versioning — directly or transitively. AV0012,
    AV0018, and AV0019 default to error severity, so an existing application that trips one of them will fail to build
    until the underlying problem is fixed, the rule is downgraded in .editorconfig, or
    <EnableApiVersioningAnalyzers>false</EnableApiVersioningAnalyzers> is set. Before these rules existed, an
    application should have either encountered runtime exceptions or not functioned as expected. These rules are catching
    mistakes early rather than imposing specific dogma about how your application must be defined.

ASP.NET Core

  • AddApiVersioning() now calls AddHttpContextAccessor(). This is additive and should be transparent, but it does mean
    IHttpContextAccessor is registered in applications that previously did not have it

Documentation

The 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.

  • The wiki has been ported to GitHub Pages and is now published at dotnet.github.io/aspnet-api-versioning with search, per-page tables of contents, and side-by-side content for each supported flavor of ASP.NET
  • README badges and links throughout the repository now point at the new site
  • The old wiki pages still exist so that old links are not broken
    • All future links should link to the new content

Why change?

  • There was little-to-no control over wiki page names, which makes it difficult for SEO
  • The wiki HTML support is much more limited that GitHub Pages
    • Theming is also supported
  • The wiki was considerable in size, but you couldn't search it; now you can
  • The project started with ASP.NET Web API (Classic) a decade ago, but ASP.NET Core is now the de facto platform
    • ASP.NET Core and Web API (Classic) have been split apart
    • There will be overlap in search, but everything else is cleanly separated
  • Errors and updates. There has never been a good wa...
Read more

10.0.0

Choose a tag to compare

@commonsensesoftware commonsensesoftware released this 21 Apr 18:39

The official release for 10.0 is here! In addition to the changes in the preview releases, there are a few additional changes.

Features

All Platforms

  • 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)]

ASP.NET Core OpenAPI

  • XmlCommentsTransformer is now resolved via DI, which allows it to be re-registered with a user-defined file path
  • Public types and members are now virtual for developer extensibility

Fixes

ASP.NET Core OpenAPI

  • Fix comparison between entry and calling assembly (#1175)
  • Ensure keyed services are registered with a lowercase key (#1176)
  • Fix nested key service resolution (#1177)
  • Implement IKeyedServiceProvider when injecting ApiVersion (#1178)

Breaking Changes

ASP.NET Core OpenAPI

  • OpenAPI documents use "enum": ["1.0"] instead of "default": "1.0"
    • This has a similar effect, but removes the free-form input when the value is bounded
    • When optional, the enum value can still be deleted/removed
    • Some UIs, such as Scalar, still provide a way to provide an enumerated value that isn't in the list

Release Notes

Feedback

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.

10.0.0 Preview 2

10.0.0 Preview 2 Pre-release
Pre-release

Choose a tag to compare

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:

  1. gRPC versioning support, which I'm waiting on grpc/grpc-dotnet#2690 and grpc/grpc-dotnet#2693
  2. Coordination with Microsoft to open up types in Microsoft.AspNetCore.OpenAPI so I don't have to resort to Reflection for integration

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.

Features

All Platforms

  • Support _ prefix character when extracting API versions from a .NET namespace (#1172)
  • Generate software bill of materials (SBOM) (#1100)

Fixes

ASP.NET Core with OpenAPI

  • Build-time OpenAPI documents have empty paths (#1165, #1168)
  • Missing XML Comments (#1169)
  • Support <example> tags (#1170)

Breaking Changes

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"
            }
        ]
    }
}

Contributors

  • Thanks to @sander1095 for reporting and fixing the OpenAPI document generation in Minimal APIs (#1165)
  • Thanks to @xavierjohn for adding enhanced support to allow namespaces that start with _ (#1172)

10.0.0 Preview 1

10.0.0 Preview 1 Pre-release
Pre-release

Choose a tag to compare

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

  • Support for the deprecation response header as defined by RFC 9745 (#1128)

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-versioning extension
    • The versioned HttpClient can 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:

  1. The calls to services.AddOpenApi( "v1" ) and so on are no longer used or needed
  2. 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 Description property 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:

  • ISunsetPolicyManagerIPolicyManager<SunsetPolicy>
  • ISunsetPolicyBuilderExtensionsIPolicyBuilderExtensions
  • ISunsetPolicyManagerExtensionsIPolicyManagerExtensions

ASP.NET Web API

The 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; }

API Explorer

The following extension methods are now extension properties.

  • ApiDescription
    • GetApiVersion()ApiVersion { get; }
    • IsDeprecated()IsDeprecated { get; }
    • GetGroupName()GroupName { get; }
    • GetUniqueID()UniqueID { get; }

OData

The following extension methods are now extension properties.

  • IEdmModel
    • GetApiVersion()ApiVersion { get; }
    • IsAdHoc()IsAdHoc { get; }

OData API Explorer

The following extension methods are now extension properties.

  • ApiDescription
    • EdmModel()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.

  • HttpContext
    • ApiVersioningFeature()ApiVersioningFeature { get; }
    • GetRequestedApiVersion()RequestedApiVersion { get; }

MVC (Core)

The following types and members have been removed:

  • DefaultApiVersionGroupDescriptionProvider, which was internally identical to GroupedApiVersionDescriptionProvider
  • Obsolete constructor public EndpointApiVersionMetadataCollationProvider( EndpointDataSource endpointDataSource )
  • Removed IServiceCollectionExtensions.EnableApiVersionBinding; it's now supported without explicit registration

The following extension methods are now extension properties.

  • ActionDescriptor
    • GetApiVersionMetadata()ApiVersionMetadata { get; }
  • ControllerModel
    • GetApiVersionModel()ApiVersionModel { get; }

API Explorer

The following extension methods are now extension properties.

  • ApiDescription
    • GetApiVersion(), SetApiVersion()ApiVersion { get; set; }
    • IsDeprecated()IsDeprecated { get; }
    • GetSunsetPolicy(), SetSunsetPolicy()SunsetPolicy { get; set; }

OData

The following extension methods are now extension properties.

  • IEdmModel
    • GetApiVersion()ApiVersion { get; }
    • IsAdHoc()IsAdHoc { get; }

Versioned HTTP Client

The following extension methods are now extension properties.

  • HttpResponseMessage
    • ReadSunsetPolicy()SunsetPolicy { get; }

Contributors

  • Huge thanks to @MGessinger who implemented most of the new deprecation header support (#1151)

8.1.0

Choose a tag to compare

@commonsensesoftware commonsensesoftware released this 26 Mar 17:42

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

Choose a tag to compare

@commonsensesoftware commonsensesoftware released this 08 Dec 21:43

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

Choose a tag to compare

@commonsensesoftware commonsensesoftware released this 09 Oct 19:44

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

Choose a tag to compare

@commonsensesoftware commonsensesoftware released this 28 Dec 03:32

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

Choose a tag to compare

@commonsensesoftware commonsensesoftware released this 08 Dec 20:39

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

7.0.0 RC 1 Pre-release
Pre-release

Choose a tag to compare

@commonsensesoftware commonsensesoftware released this 26 Nov 23:33

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.