Jack
Jack

Reputation: 1

The request matched multiple endpoints on .NET Core

I use OpenAPI (Swagger) in a .NET Core project and when using multiple methods that have similar get requests, I encounter "Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints." error during runtime. I look at several pages on the web and SO and tried to apply the workarounds like The request matched multiple endpoints but why?, but it does not fix the problem. Here are the API methods and route definitions that I use.

[Route("get", Name="get")]
public IEnumerable<DemoDto> Get()
{
    //
}

[Route("get/{id}", Name="getById")]
public DemoDto GetById(int id)
{
    //
}

[Route("get/{query}", Name="getWithPagination")]
public IEnumerable<DemoDto> GetWithPagination(DemoQuery query)
{
    //
}

I use Name property in order to fix the problem but not solved. Any idea to make changes on the routes to differentiate Get() and GetWithPagination()?

Upvotes: 4

Views: 18910

Answers (3)

Gokhan Turkben
Gokhan Turkben

Reputation: 101

ASP.NET Web API 2 supports a new type of routing. Offical Doc

Route constraints let you restrict your parameters type and matched with these types (int, string, even date etc). The general syntax is "{parameter:constraint}"

[Route("users/{id:int}")]
public User GetUserById(int id) { ... }

[Route("users/{name}")]
public User GetUserByName(string name) { ... }

I tested at API;

//match : api/users/1 
[HttpGet("{id:int}")]
public IActionResult GetUserById(int id){ ... }

//match : api/users/gokhan
[HttpGet("{name}")]
public IActionResult GetUserByName(string name){ ... }

Upvotes: 0

Jonesopolis
Jonesopolis

Reputation: 25370

[Route("get/{query}", Name="getWithPagination")]

This doesn't make sense. DemoQuery is an object, it can't be represented by a single part of a url. You can tell the ModelBinder to build your object from multiple query parameters, though.

The routing engine is getting this route confused with the [Route("get/{id}", Name="getById")] route. They both appear to match get/blah.

In addition to fixing your DemoQuery route, try adding a route constraint on the id route -

[Route("get/{id:int}", Name="getById")]

to better help the engine.


To get DemoQuery to work, assume it looks something like:

public class DemoQuery
{ 
     public string Name { get; set; }
     public int Value { get; set; }
}

Then change your action to

[Route("getPaged/{query}", Name="getWithPagination")]
public IEnumerable<DemoDto> GetWithPagination([FromQuery] DemoQuery query)

and call then endpoint like /getPaged?name=test&value=123. And the ModelBinder should build your object for you.

Upvotes: 5

Yaroslav Bres
Yaroslav Bres

Reputation: 1317

You have two endpoints with equals routes: get/{id} and get/{query}.

If you write in browser line: get/123, the system can't understand what route to use, because they have the same pattern.

You need to distinguish them and I suggest you use restful style for routes, like: item/{id}, items?{your query}

Upvotes: 5

Related Questions