-
Notifications
You must be signed in to change notification settings - Fork 711
Api Versioning break CreatedAt on MVC Core 2.2 #409
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
Comments
@vanbukin I had same thing and am raising issue on aspnetcore. you can get behaviour back if you set |
I'll link to this issue just in case the issue is here but I think it's the new Endpoint Routing |
@vanbukin, @AdamWillden is correct. 2.2 introduces a new type of routing system called Endpoint Routing, which is the new default. You can use the legacy routing mechanism by disabling this in the options. I've been aware of this change for some time and, in fact, some of those design driving the routing changes come from my feedback. Unfortunately, the ASP.NET has an entire platform team and I'm just one guy. I'm not even part of the ASP.NET team.
That said, I'm working toward supporting this as quickly as possible. The largest barrier isn't the changes in code, but the amount of testing and coordinating that the API Versioning 3.0 release. The 3.0 release brings a lot of fixes and other great features that do not depend on 2.2. If I jump the gun and force that immediately, all library consumers have to move up to 2.2, which is almost certainly not viable for everyone. I had a recent chat with the ASP.NET team and their LTS story will be on 2.1 and that isn't expected to change again until 3.1. My current plan is to release 3.0, which only depends on 2.1. That will have a good story for existing adopters for the foreseeable future. I don't have the capacity to maintain a ton of version variations, so I definitely won't backport features and bug fixes will have to absolutely critical for me to consider them on older versions. The reported issues have dropped significantly since the Beta 2 release, which indicates stability and has given me some bandwidth. I anticipate that the official release will be later this month. The changes to support Endpoint Routing should be mostly internal shuffling and minor refactoring. I don't have a firm date, but I anticipate that it will be sometime in January. I know the community is champing at the bit for this. I'm going as fast as my fingers and physics allow, but - again - I'm just one guy. I still have to do my day job on top of it. Thanks for you patience. |
Not only |
3.1 has been published and includes support for Endpoint Routing. All of the sample applications have been updated to use Endpoint Routing by default as well. Thanks. |
@commonsensesoftware You are awesome! Thank you! |
@vanbukin let me know if you're still experiencing issues, I'm still seeing same issue with new 3.1 package. |
I can confirm that there was indeed a bug in the ApiVersionRouteConstraint with Endpoint Routing. The new URL generation mechanism can call IRouteConstraint instances with a The example here is similar to the scenario you are describing. The only difference is that it uses I tweaked it ever so slightly to repro your exact scenario: [ApiController]
[ApiVersion( "1.0" )]
[Route( "api/v{version:apiVersion}/[controller]" )]
public class HelloWorldController : ControllerBase
{
[HttpGet]
public IActionResult Get( ApiVersion apiVersion ) =>
Ok( new { Controller = GetType().Name, Version = apiVersion.ToString() } );
[HttpGet( "{id:int}" )]
public IActionResult Get( int id, ApiVersion apiVersion ) =>
Ok( new { Controller = GetType().Name, Id = id, Version = apiVersion.ToString() } );
[HttpPost]
public IActionResult Post( ApiVersion apiVersion ) =>
CreatedAtAction( nameof( Get ), new { id = 42, version = apiVersion.ToString() }, null );
} Here's the results of calling POST: POST /api/v1/helloworld
Host: localhost:5000 HTTP/1.1 201
Content-Length: 0
Location: http://localhost:5000/api/v1/HelloWorld/42
api-supported-versions: 1.0 This demonstrates that You might want to make sure you've done a restore and clean build with the latest update. You might also check and/or report the stack trace to confirm it's happening within API versioning. Given the information you've provided, I'm not repro'ing your scenario (anymore). I'm happy to investigate further with some more info. |
BTW: support for the ApiVersion as a model-bound action parameter is a new feature 3.0. This way you don't have to hardcode the values nor use |
I went one step further. |
I've tried your example from above and I got an error saying that the API version is not specified. Had to use the following options to get it to work:
|
Are you trying to use |
Hello, Sorry for that. I'm using the |
No problem. It appears the primary reason it's not working for you is that you have not applied the ApiVersionRouteConstraint. This is required when versioning by URL segment. Your route template is: [Route( "api/v{version}/[controller]" )] But it should be: [Route( "api/v{version:apiVersion}/[controller]" )] apiVersion is the default name associated with the route constraint. It's possible to change this name in the options if you really want to. The name version is your user-defined route parameter name. This can be named whatever you want, but I usually use version in the examples. I hope that helps. |
Aha, it makes sense now! Thank you! |
Hey @commonsensesoftware , I also got this problem using
I understood the conversation above as I'm using |
@elonmallin, you didn't provide information about your controller or action, but I'm willing to guess that you're versioning by URL segment as in the examples above. Based on what you've provided, I surmise that you are simply not including the API version as one of the route parameters for URL generation. I can't say why the legacy routing system automatically has the route parameter populated, but Endpoint Routing doesn't. You should be able to resolve things using one of the following: Option 1Explicitly retrieve the requested API version and specify it in the route generation process. public async Task<IActionResult> Post([FromBody] User user)
{
var version = Request.HttpContext.GetRequestedApiVersion().ToString();
return CreatedAtAction(nameof(GetUser), new { id = user.Id, version }, await GetUser(user.Id));
} Option 2Implicitly retrieve the requested API version via model binding and specify it in the route generation process. public async Task<IActionResult> Post([FromBody] User user, ApiVersion apiVersion)
{
var version = apiVersion.ToString();
return CreatedAtAction(nameof(GetUser), new { id = user.Id, version }, await GetUser(user.Id));
} |
Okey, thanks! I'll try Option 1 since I'm setting the version in the route as you suspected. Do you know if this will be made to work without any of these workarounds in the future? |
Doubtful. I wouldn't consider this a workaround. You should specify the version route parameter using this method IMO. The current route and target route do not have to have the same API version. This is a consequence of versioning by URL segment (the least RESTful method). All other built-in versioning methods do not have this problem. |
Okey, yea that's true. However the current and target route doesn't have to be on the same controller either I guess. But it's the default. I thought the whole controller path including version would be the default when using the CreatedAtAction function. If other built in versioning methods doesn't have this problem it would be more consistent too I guess if this method didn't have this "problem" either. But I guess it has to do with how query params are passed along by default and the [controller] is also deeply ingrained in the routing system or something. |
Agreed; they don't have to be same controller. Be aware that the route tables are not API version aware. This may require you to create a route naming convention which bakes in the API version; for example, "GetUserV1" or "GetUserV2". The reason other versioning methods do not suffer from this problem is because the API version is not in the route template (e.g. the path). Query parameters, headers, etc are specified by the client - as they should be. The server's job is not to tell the client which version they want. By definition of the Uniform Interface constraint, the path |
If I make
GET
request on http://localhost:5000/api/v1/values/42, then I've got the following resultand it's ok. Bui if I make a
POST
on http://localhost:5000/api/v1/valueswith following body
I've got the following stacktrace
I can put breakpoint inside
Post
action and see that it calls correctly. The problem is somewhere inside CreatedAtAction.Here is minimal repro
.csproj
and Program.cs
The text was updated successfully, but these errors were encountered: