-
Notifications
You must be signed in to change notification settings - Fork 697
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CurrentImplementationApiVersionSelector while versioning by URL path #43
Comments
There are a couple of different issues going on here so let me try to break up the response into pieces. URL Path VersioningWhen you version your API in the URL path, you can't logically have a default version. The API version is instrinsically part of the path. In your example, you have the route template Most service authors that use URL path versioning prefix the API version segment value with the letter 'v'. This would make the route template The method in which the requested API version is internally set is - ever so slightly - different that any other method. All other methods go through the IApiVersionReader to extract the API version from the incoming request message. Trying to understand and parse the URL path in the same manner would be difficult and brittle. Since ASP.NET already provides a structured way to parse route templates, URL path versioning uses a route constraint instead. This allows you to craft your URLs however you want and just indicate which segment the API version should be extracted from. You can use the route template as you defined it, but there is no way to assume a default because there are no matching candidates. Default Version SelectionIt may not be intrinsically obvious, but the DefaultApiVersion and ApiVersionSelector options are somewhat mutually exclusive. The purpose of the DefaultApiVersion is to simply define an assumed version without hard-coding the value for all fallback cases because every service always has some logical version number, even if it's not formally defined. The IApiVersionSelector is the extension point to select the appropriate API version given a request and the discovered API version model. The infrastructure does all the hard work of collecting the available API versions and you select the best one. In your case, you elected to use the CurrentImplementationApiVersionSelector and have the following API versions defined:
This selector will always choose 3.0 from these choices. The only time it would ever use the default configured API version of 2.0 is if there were no candidate API versions to select from. For example, if your versions were all pre-release:
Any version with a status is not considered implemented. Additionally, deprecated does not mean not implemented. If your intent was to have all clients that don't request a version start on 2.0, then you can just set the DefaultApiVersion. The default value for the ApiVersionSelector is an instance of the DefaultApiVersionSelector, which just always uses the value of the configured DefaultApiVersion. Faking a Default API Version with URL PathsThere is one way that you can give the impression of an implicitly-version URL path. To enable this, you need to make multiple routes per controller. API versioning stays out of the way of routing and only gets involved with resolving the appropriate controllers and actions. For example, if your controllers were updated with additional routes: [ApiVersion( "1.0", Deprecated = true )]
[Route( "api/uri" )]
[Route( "api/{version:apiVersion}/uri" )]
public class UriController : ApiController { /* ommitted */ }
[ApiVersion( "2.0" )]
[Route( "api/uri" )]
[Route( "api/{version:apiVersion}/uri" )]
public class Uri2Controller : ApiController { /* ommitted */ }
[ApiVersion( "3.0" )]
[Route( "api/uri" )]
[Route( "api/{version:apiVersion}/uri" )]
public class Uri3Controller : ApiController { /* ommitted */ } Your controllers will be resolved using the following URLs:
The last 3 entries are there because the default configuration uses an IApiVersionReader that extracts the API version from the api-version query string parameter. If you want to remove this behavior, you can implement a reader that always returns null. public class IgnoreApiVersionReader : IApiVersionReader
{
public string Read( HttpRequestMessage request ) => null;
} You may have noticed that the example used the names UriController, Uri2Controller, and Uri3Controller. In setting up an example that would simulate your scenario, I found an edge case bug. I'll create a new issue for this bug and correlate it back to this thread. For now, using different type names will make this setup work. I hope that helps. |
You well explained the problem with URL path versioning and DefaultApiVersion. Multiple routes on controller makes it bit confusing so i'm considering to choose e.g Custom Header versioning as this one fits better my scenario. Anyway thanks a lot for answer and solution. Cheers! |
Is the CurrentImplementationApiVersionSelector working while using URL path versioning? In case of header versioning everything works fine but in case of URL path versionig always the first version(1.0) of the controller is selected even if the another version(2.0) is specified as DefaultApiVersion.
Controllers:
WebApiConfig:
The text was updated successfully, but these errors were encountered: