Skip to content

I am getting ApiVersionUnspecified in response #86

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

Closed
mayureshs opened this issue Feb 15, 2017 · 8 comments
Closed

I am getting ApiVersionUnspecified in response #86

mayureshs opened this issue Feb 15, 2017 · 8 comments
Assignees

Comments

@mayureshs
Copy link

Chris - can you help. Not sure why its not working. I have uploaded the startup and the api controller file. I am trying to hit the api --> http://localhost:16460/api/v1/tfmemployee but i get an error
{
"error": {
"code": "ApiVersionUnspecified",
"message": "An API version is required, but was not specified."
}
}

Startup.txt
TfmemployeeController.txt

@mayureshs
Copy link
Author

mayureshs commented Feb 15, 2017

I got that resolved by change [RoutePrefix()] to [Route()]. But now when i create an V2 version , i can only invoke V1, v2 gives me the following message. See attached file. What am i missing ?

TfmEmployeeControllerV2.txt

http://localhost:16460/api/v2/tfmemployee

{
"error": {
"code": "UnsupportedApiVersion",
"message": "The HTTP resource that matches the request URI 'http://localhost:16460/api/v2/tfmemployee' does not support the API version '2'.",
"innerError": {
"message": "No route providing a controller name with API version '2' was found to match request URI 'http://localhost:16460/api/v2/tfmemployee'."
}
}
}

@commonsensesoftware
Copy link
Collaborator

Ok ... I almost thought you hit a bug because I was running into the same problem trying to create a repo. It turns out that we hit one of the wonderful issues with the routing infrastructure in Web API. Web API uses the convention [Name]Controller to match route segments to controller types. The entire issue was with how you named the controller class. >_< Silly I know.

This will work:

[ApiVersion( "1.0" )]
[RoutePrefix( "api/v{version:apiVersion}/tfmemployee" )]
public class TfmEmployeeController : ApiController
{
    [Route]
    public IHttpActionResult Get() => Ok( "Success" );
}
[ApiVersion( "2.0" )]
[RoutePrefix( "api/v{version:apiVersion}/tfmemployee" )]
public class TfmEmployee2Controller : ApiController
{
    [Route]
    public IHttpActionResult Get() => Ok( "Success from V2" );
}

Notice how the "V2" is moved before the "Controller" suffix. Just to illustrate that this is not related to API versioning, you can disable or comment it out in Startup.cs. Then define your controllers this way:

[RoutePrefix( "api/v1/tfmemployee" )]
public class TfmEmployeeController : ApiController
{
    [Route]
    public IHttpActionResult Get() => Ok( "Success" );
}
[RoutePrefix( "api/v2/tfmemployee" )]
public class TfmEmployeeControllerV2 : ApiController
{
    [Route]
    public IHttpActionResult Get() => Ok( "Success from V2" );
}

Now we have two different controllers with completely different routes and API versioning is not involved or enabled. You'll see that a request to ~/api/v2/tfmemployee will return 404. If you move the "V2" before "Controller", then it will start working. I'm sorry you hit this landmine. I wish there was something I could do about it. The only highlight is that routing was completely rewritten in ASP.NET Core to remove wonkiness like this!

Let me know if you continue to be stuck.

@mayureshs
Copy link
Author

mayureshs commented Feb 15, 2017

Thank you ! That helped and its working fine. One last thing, can you eyeball this startup file to see if i have the versioning setup correctly. I would like every api under this project to have a version in the request URL.

startup.txt

@commonsensesoftware
Copy link
Collaborator

Based on what I saw, it looks correct. Once you enable API versioning by calling AddApiVersioning all services will now have versioning enforced (error on the safe side). This is true even if a controller does not declare a version via the [ApiVersion] attribute (this is so that services can be easily grandfathered in without changing). The API version used in these cases is the value defined in the ApiVersioningOptions.DefaultApiVersion. It's default value is version 1.0.

I recommend always explicitly defining your API versions so that it's obvious in the code, but if you want to experiment with the behavior all you have to do is comment out [ApiVersion("1.0")] on your first controller implementation. You'll see that it still works when you can for ~/api/v1/*. The value comes from that default setting.

Any controller (e.g. service) that does not want this behavior must either explicitly declare their API versions or opt-out of API versioning all together using [ApiVersionNeutral]. API version-neutral controllers will accept any API version.

I hope that helps.

@mayureshs
Copy link
Author

Super ! thanks will share my feedback on how it goes. Thank you !

@commonsensesoftware
Copy link
Collaborator

It appears you got what you needed on this topic. Feel free to re-open this issue or start a new discussion as needed.

@sirajzarook
Copy link

Hi

I had to remove Microsoft.AspNetCore.Mvc.Versioning" Version="1.2.1" from Core API project and rollback to version 1.0.3 after I was unable to work with inconsistency.

I was simply trying to standard redirect extension methods in as shown below which is not firing with version 1.2.0 on wards.
app.UseStatusCodePagesWithReExecute("/error/{0}");
app.UseExceptionHandler("/error/500");

The suggestion in this article worked but with inconsistency so not using it.

I am definitely downgrading to 1.0.3 for now.

regards
Si Zi

@commonsensesoftware
Copy link
Collaborator

Things are likely more consistent than you think. Prior to 1.1, there was and still is a different issue where a route might not be discovered. This is because the IActionSelector can be visited multiple times by the ASP.NET infrastructure. The only way to guarantee that the correct decision is made is by visiting all possible candidates. In order to make that happen, the IActionSelector has to continue to report success, even when it doesn't know whether the final result will be successful or not. The final decision is made by the IApiVersionRoutePolicy. Of course, if every possibility had to be enumerated each time, that would be highly inefficient. After a route has traversed all possibilities at least once, the policy can be enforced much earlier in the pipeline.

Unfortunately, this behavior doesn't always play nice with other middleware. The initial API versioning policy will be enforced at the end of the pipeline, which will not trigger other middleware that might have performed a redirect, etc from a failed request (e.g. 400, 404, or 405). A second pass will likely yield the correct behavior because the decision can be made before the end of the pipeline.

This was a similar issue in #146, but was resolved. I make every reasonable effort to have API versioning play nice with other middleware and behaviors. If you can explain exactly what you're hoping to achieve, I can try to help. If you have the world's simplest repro, that would go a long way and accelerate my investigation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants