Search code examples
c#asp.net-core-webapiasp.net-web-api-routing

.Net 6 Web API: Multiple Base Routes AND Named Routes


I'm working on converting an ASP.NET Web API 2 to a .Net 6 Web API and ran into a problem when using Versioning.

The problem I'm running into concerns named routes.

I want my API to be able to be called with the version in the query string, route, and headers. ie:

https://localhost:1234/api/v1/helloworld
https://localhost:1234/api/helloworld?api-version=1.0
https://localhost:1234/api/v2/helloworld
https://localhost:1234/api/helloworld?api-version=2.0

One of my controller methods already has 3 different routes. The reason is because the code is all the same except the call to the database. I use a switch statement to determine which route was called. For this, I give each route a name. ie:

[...]

[ApiVersion("1.0")]
[Route("api/[controller]")]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiController]
public class HelloWorldController : ControllerBase {

    [HttpGet("1", Name="Route1")]
    [HttpGet("2", Name="Route2")]
    [HttpGet("3", Name="Route3")]
    public async Task<IActionResult> Get() {
        List<Car> model;

        switch (ControllerContext.ActionDescriptor.AttributeRouteInfo?.Name) {
            case "Route1":
                model = await _repo.FindByRoute1(...).ToListAsync();
            case "Route2":
                model = await _repo.FindByRoute2(...).ToListAsync();
            case "Route3":
                model = await _repo.FindByRoute3(...).ToListAsync();
        }
        
        return Ok(model);
    }
}

[...]

The error I am getting is

Error 1:
Attribute routes with the same name 'Route1' must have the same template:
Action: 'Controllers.V2.HelloWorldController.Get' - Template: 'api/helloworld/1'
Action: 'Controllers.V2.HelloWorldController.Get' - Template: 'api/v{version:apiVersion}/helloworld/1'

How can I use named routes AND multiple base routes?


Solution

  • Jsut as the error indicates,your controller methods have 6 routes instead of 3 routes,your codes would perform the same as below:

        [ApiController]
            [Route("api/{version}/[controller]/1", Name = "Route1")]
            [Route("api/[controller]/1", Name = "Route1")]
            [Route("api/{version}/[controller]/2", Name = "Route2")]
            [Route("api/[controller]/2", Name = "Route2")]
            [Route("api/{version}/[controller]/2", Name = "Route3")]
            [Route("api/[controller]/2", Name = "Route3")]
            public class HelloWorldController : ControllerBase
            {
              .....
            }
    

    And in .net core Route names must be unique application-wide as mentioned in this document