-
Notifications
You must be signed in to change notification settings - Fork 707
Migration
This topic serves as the guide for migrating from version <= 5.x.x
to version >= 6.0.0
. The majority of this information has been outlined in previous discussions.
If you'd like more information on the background context, you can read the Hello Project "Asp" announcement.
For the most part, you can expect the required changes to be a new package identifier and different namespaces. It is entirely possible that you may update those and find the rest of the code to be identical. The mileage will vary depending on your level of customization, but you can expect the changes to be trivial in most cases.
The original Microsoft.*
packages are now deprecated and will only undergo servicing:
Platform | Package | Version | TFM |
---|---|---|---|
ASP.NET Web API | Microsoft.AspNet.WebApi.Versioning | <= 5.x.x | net45 |
ASP.NET Web API | Microsoft.AspNet.WebApi.Versioning.ApiExplorer | <= 5.x.x | net45 |
ASP.NET Web API | Microsoft.AspNet.OData.Versioning | <= 5.x.x | net45 |
ASP.NET Web API | Microsoft.AspNet.OData.Versioning.ApiExplorer | <= 5.x.x | net45 |
ASP.NET Core | Microsoft.AspNetCore.Mvc.Versioning | <= 5.x.x | netcoreapp3.1, net5.0 |
ASP.NET Core | Microsoft.AspNetCore.Mvc.ApiExplorer | <= 5.x.x | netcoreapp3.1, net5.0 |
ASP.NET Core | Microsoft.AspNetCore.OData | <= 5.x.x | netcoreapp3.1, net5.0 |
ASP.NET Core | Microsoft.AspNetCore.OData.ApiExplorer | <= 5.x.x | netcoreapp3.1, net5.0 |
All new features and platform support will use the Asp.Versioning.*
prefix:
Platform | Package | Version | TFM |
---|---|---|---|
All | Asp.Versioning.Abstractions | 6.0.0+ | net6.0+, netstandard1.0, netstandard2.0 |
ASP.NET Web API | Asp.Versioning.WebApi | 6.0.0+ | net45, net472 |
ASP.NET Web API | Asp.Versioning.WebApi.ApiExplorer | 6.0.0+ | net45, net472 |
ASP.NET Web API | Asp.Versioning.WebApi.OData | 6.0.0+ | net45, net472 |
ASP.NET Web API | Asp.Versioning.WebApi.OData.ApiExplorer | 6.0.0+ | net45, net472 |
ASP.NET Core | Asp.Versioning.Http1 | 6.0.0+ | net6.0+ |
ASP.NET Core | Asp.Versioning.Mvc2 | 6.0.0+ | net6.0+ |
ASP.NET Core | Asp.Versioning.Mvc.ApiExplorer3 | 6.0.0+ | net6.0+ |
ASP.NET Core | Asp.Versioning.OData | 6.0.0+ | net6.0+ |
ASP.NET Core | Asp.Versioning.OData.ApiExplorer | 6.0.0+ | net6.0+ |
All | Asp.Versioning.Http.Client | 6.0.0+ | net6.0+, netstandard1.1, netstandard2.0 |
[1] Base library that supports Minimal APIs
[2] MVC Core with controller support
[3] Supports exploration of Minimal APIs and controllers
As the project is no longer part of Microsoft, all namespaces have become Asp.Versioning.*
. It didn't make sense to keep using Microsoft.*
when things don't line up. Furthermore, what namespace should all new code live under? Continuing to use the Microsoft
namespace seemed wrong. An interesting benefit, however, is that using Api.Versioning.*
allows for more consistency across the ASP.NET Web API and Core implementations. The existing differences in library namespaces for shared code often led to conditional compiler directives. For ease of use, extension methods will continue to live in the namespace they correspond to.
The format and default implementation has not changed, but parsing has been broken apart. The new IApiVersionParser
service has been introduced to support this capability. ApiVersion.Parse
and ApiVersion.TryParse
have been removed, but are replaced by ApiVersionParser.Default
, which will provide a default implementation.
ApiVersion.GroupVersion
in .NET 6.0 and beyond is now represented as DateOnly
. DateOnly
accurately represents how a group version or date version was always meant to be, but couldn't be represented without introducing its own type due to the design of DateTime
. The .NET Standard and .NET Framework representations will continue to use DateTime
.
IApiVersionReader.Read
now returns IReadOnlyList<string>
instead of string?
. There are a few reasons for this change. First, the Null Mistake is removed as an empty list is completely acceptable. Second, it was entirely possible for a particular reader implementation to return more than one value. Consider that ?api-version=1.0&api-version=2.0
would return both 1.0
and 2.0
. In previous versions, the implementation would instead throw AmbiguousApiVersionException
that would have to be handled. That behavior becomes problematic for the server to correctly report the response to the client. Reading multiple API version values in and of itself isn't exceptional, it's just an invalid client request. ApiVersionReader.Combine
also enables combining different types of readers through composition. Readers for different parts of a request are even more likely to return different values. Refactoring to return a list makes it very simple to return all of the raw API versions provided without any exceptions and regardless of where they were read from.
In versions >= 2.1.0 && < 6.0.0
, the ApiVersioningOptions
provided the property UseApiBehavior
. This setting was a bridge to the API Behaviors feature introduced in ASP.NET Core 2.1. In earlier versions of ASP.NET Core, there was not a clear way to disambiguate between a UI and API controller. Adding API Behaviors via [ApiController]
to a controller or assembly provided a way to solve that problem. API Versioning subsequently added two new services that align to it:
-
IApiControllerFilter
- filters out non-API controllers -
IApiControllerSpecification
- determines whether a controller is for an API
The default filter is an aggregation over all specifications. The default specifications look for API Behaviors and OData routing.
In the 2.1.x
timeframe, this was a behavioral breaking change. To facilitate a smoother transition, the UseApiBehavior
option was introduced with a value of false
, which maintained the existing behavior. Starting in 3.0
, the value defaulted to true
, which only considers controllers with API Behaviors applied. Starting in 6.0
, the property has been completely removed as it is no longer necessary.
IApiControllerFilter
and any of the IApiControllerSpecification
services can be modified through dependency injection. To align with the legacy behavior of UseApiBehavior = false
, you can use the NoControllerFilter
implementation:
builder.Services.AddTransient<IApiControllerFilter, NoControllerFilter>();
builder.Services.AddApiVersioning().AddMvc();
IReportApiVersions.Report
now accepts the entire HTTP response as opposed to just the headers. Accepting only the headers was an over-normalization that wasn't really necessary. Additional information was also necessary to support Sunset Policies. The Report
overload that accepts Lazy<ApiVersionModel>
has been removed as it's no longer used or necessary.
Extension methods related to retrieving an ApiVersionModel
have been supplanted by the new extension method GetApiVersionMetadata()
. The GetApiVersionModel()
extension method, for example, was a shortcut for GetApiVersionModel(ApiVersionMapping.Explicit)
. A new type - ApiVersionMetadata
- has been introduced that unifies the metadata implementation across ASP.NET platforms. In most cases, this information was retrieved from HttpActionDescriptor
in ASP.NET Web API and ActionDescriptor
in ASP.NET Core. In ASP.NET Core, this information is
now stored in the ActionDescriptor.EndpointMetadata
and Endpoint.Metadata
collections (depending on context).
The following is the mapping between the old and new extension methods:
GetApiVersionModel(ApiVersionMapping) → GetApiVersionMetadata()
GetApiVersionModel() → ApiVersionMetadata.Map(ApiVersionMapping.Explicit)
MappingTo(ApiVersion) → ApiVersionMetadata.MappingTo(ApiVersion)
IsMappedTo(ApiVersion) → ApiVersionMetadata.IsMappedTo(ApiVersion)
The IErrorResponseProvider
service had been the hook to provide custom error responses. Problem Details (RFC 7807) had only just been ratified when this project started and they were not part of ASP.NET yet. ASP.NET Core eventually added first-class support for Problem Details and IErrorResponseProvider
had an adapter implementation for alignment in previous versions. Now that Problem Details are the de factor method for error reporting, it no longer makes sense to retain IErrorResponseProvider
and it has been removed.
The error responses bodies provided by IErrorResponseProvider
complied with the Microsoft REST Guidelines error response format, which is itself the error response format used by the OData protocol (see OData JSON Format §21.1). If you need to retain that format, the Error Response Backward Compatibility topic discusses how to enable it.
ProblemDetails.Type
could logically be used to model the established error Code
; however, the value is supposed to be a URI. For backward compatibility, the existing error codes will be emitted as the Code
extension in Problem Details. The Error Responses topic provides details for each well-known problem that may be returned in responses.
The legacy, convention-based routing with IActionSelector
has been dropped. Limitations in the original ASP.NET Core routing design caused a number of issues and inconsistencies, which were resolved when Endpoint Routing was introduced; especially 405
or 415
responses. The primary reason it continued to be supported was waiting for OData to support Endpoint Routing, which it does as of 8.0
.
The routing logic has been updated to properly return a response for 404
, 405
, 406
, and 415
. Due to necessary API Versioning fixes and the way routing works in ASP.NET Core, it is no longer possible to always report 400
when an API version could be matched, but doesn't. In some of these cases it is also not possible to add ProblemDetails
; especially prior to .NET 7 because ASP.NET Core did not provide a hook for it.
ASP.NET Web API will have parity with these behaviors, even though the routing system is completely different. API Versioning has more control over the routing system in Web API so for the most part the only thing that will change is the status code.
What happens when an API version could match, but doesn't has always been a bit of a gray area. The general consensus seems to be that developers don't care because it's a client error or they expect it to be 404
. These default rule will continue to return 400
when versioning by query string or header, but that can now be changed via ApiVersioningOptions.UnsupportedApiVersionStatusCode. Versioning by URL segment will always return 404
. Versioning by media type will always return 406
or 415
.
The UseApiVersioning()
middleware in ASP.NET Core has been removed. It never did anything except setup the IApiVersioningFeature
in the current request, which doesn't require middleware.
Applies to ASP.NET Core only. The setup and extension methods in ASP.NET Web API are unchanged.
Support for Minimal APIs and OData in ASP.NET Core required some changes to how services are configured in an application. The new IApiVersioningBuilder
interface provides a way to hang all API Versioning related extensions off of. This approach also helps address extension method naming conflicts and scenarios where you might forget to register another set of required services. If you referenced and enabled everything supported by API Versioning, then your configuration might look like:
var builder = WebApplication.CreateBuilder( args );
var services = builder.Services;
services.AddApiVersioning() // Core API Versioning services with support for Minimal APIs
.AddMvc() // API version-aware extensions for MVC Core with controllers (not full MVC)
.AddApiExplorer() // API version-aware API Explorer extensions
.AddOData() // API versioning extensions for OData
.AddODataApiExplorer(); // API version-aware API Explorer extensions for OData
- As noted above,
ApiVersioningOptions.UseApiBehaviors
has been removed -
ApiVersioningOptions.Conventions
has been moved toMvcApiVersioningOptions.Conventions
as API Versioning no longer requires MVC Core- To configure conventions, use
.AddMvc(options => options.Conventions = ?)
via theIApiVersioningBuilder
extension method
- To configure conventions, use
-
ApiVersioningOptions.ControllerNameConvention
has been removed as an explicit option, but can be changed via dependency injection- To configure a different naming convention, use
builder.Services.AddSingleton<IControllerNameConvention, OriginalControllerNameConvention>()
- To configure a different naming convention, use
- Home
- Quick Starts
- Version Format
- Version Discovery
- Version Policies
- How to Version Your Service
- API Versioning with OData
- Configuring Your Application
- Error Responses
- API Documentation
- Extensions and Customizations
- Known Limitations
- FAQ
- Examples