Aspnet-api-versioning: When different version name labels - No route matches the supplied values

Created on 4 Dec 2017  路  4Comments  路  Source: microsoft/aspnet-api-versioning

Hi. Can you explain why controllers pair below didnt work?

    [ApiVersion("1.0")]
    [Route("api/{version1:apiVersion}/[controller]")]
    public class ItemsController: Controller
    {
        [HttpGet]
        public string Get(int id)
        {
            return "value";
        }
    }

    [ApiVersion("1.0")]
    [Route("api/{version:apiVersion}/[controller]")]
    public class ValuesController : Controller
    {
        // GET api/values
        [HttpGet]
        public IActionResult Get()
        {
            return CreatedAtAction("Get", "Items", new {id = 1}, "text");
        }
}

Please, notice that they have different apiVersion labels: version and version1.
I can call Items get method, but CreatedAtAction didn't work: System.InvalidOperationException: No route matches the supplied values.
If i change label for routes template for equals - it works.
May be it has some connection with #131?

answered asp.net core question

Most helpful comment

Not sure about your setup. I noticed that you don't have a leading v in your route template for the API version segment. I'm not sure if that's intentional or not. The letter v is not part of a well-formed API version value. It's not required, but most service authors want something like api/v1/values.

After looking at your setup, I realized that the issue is that you are not providing the API version route parameter. Since you are versioning using a URL segment, you must provide this value. If you want the value to be used based on the current request, you can get the value using the built-in extension method. Also note that since you used the name version1, the same name must be used in the route values. The implementation should look like:

```c#
[ApiVersion( "1.0" )]
[Route( "api/v{version:apiVersion}/[controller]" )]
public class ValuesController : Controller
{
[HttpGet]
public IActionResult Get() =>
Ok( new
{
id = 42,
link = Url.Link( "ItemsV1", new { id = 1, version1 = ApiVersion } )
} );

string ApiVersion => HttpContext.GetRequestedApiVersion().ToString();

}

The request:
```http
GET /api/v1/values HTTP/1.1
Host: localhost:62289
````
Produces this response:
```http
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 56

{"id":42,"link":"http://localhost:62289/api/v1/Items/1"}

I've attached a working end-to-end example you can follow. ApiVersionRouteParam.zip

All 4 comments

The routing does not look correct. Try this:

```c#
[ApiVersion("1.0")]
[Route("api/{version1:apiVersion}/[controller]")]
public class ItemsController: Controller
{
[HttpGet("{id:int}")]
public string Get(int id)
{
return "value";
}
}

[ApiVersion("1.0")]
[Route("api/{version:apiVersion}/[controller]")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
public IActionResult Get()
{
return CreatedAtAction("Get", "Items", new {id = 1}, "text");
}
}
```

The difference between version and version1 is irrelevant. Those are user-defined and can be whatever you want them to be in your route template. The apiVersion can be changed, but that's the default mapping and generally not worth changing.

Also, not be completely pedantic, but CreateAtAction is usually only used in a POST. Keep in mind that the route system doesn't expect or support versioned route names and the resolution process will resolve the incorrect route with this configuration (due to the URL segment). You can look at this example that I provided that shows the proper usage. You'll likely want to use an explicit route name with the version embedded in it (ex: "ItemsV1").

I hope that helps.

Hi! First of all - thanks for reply.
I know about using CreateAtAction in a POST - this just a synthetic example - can be tested using browser only.
It turns out that the user _version_ and _version1_ still play a role - if using the same error is gone.
In addition, I tried to use the [HttpGet("{id:int}")] - the behavior has not changed.

Not sure about your setup. I noticed that you don't have a leading v in your route template for the API version segment. I'm not sure if that's intentional or not. The letter v is not part of a well-formed API version value. It's not required, but most service authors want something like api/v1/values.

After looking at your setup, I realized that the issue is that you are not providing the API version route parameter. Since you are versioning using a URL segment, you must provide this value. If you want the value to be used based on the current request, you can get the value using the built-in extension method. Also note that since you used the name version1, the same name must be used in the route values. The implementation should look like:

```c#
[ApiVersion( "1.0" )]
[Route( "api/v{version:apiVersion}/[controller]" )]
public class ValuesController : Controller
{
[HttpGet]
public IActionResult Get() =>
Ok( new
{
id = 42,
link = Url.Link( "ItemsV1", new { id = 1, version1 = ApiVersion } )
} );

string ApiVersion => HttpContext.GetRequestedApiVersion().ToString();

}

The request:
```http
GET /api/v1/values HTTP/1.1
Host: localhost:62289
````
Produces this response:
```http
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 56

{"id":42,"link":"http://localhost:62289/api/v1/Items/1"}

I've attached a working end-to-end example you can follow. ApiVersionRouteParam.zip

Thank you, it's clear now. 馃憤

Was this page helpful?
0 / 5 - 0 ratings