Hugo Vrana
Hugo Vrana

Reputation: 303

ASP.NET Core API Controller ambiguous method issue

I came across this issue, and couldn't find a quick guide to is, so here I am.

I've created and ASP.NET Core API.

On one controller, i've defined 2 get methods. Each accepts different parameter, but both are Strings. This creates following issue.

Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints. Matches: 

Airbnb.Controllers.ListingsAndReviewsController.GetById (Airbnb)
Airbnb.Controllers.ListingsAndReviewsController.GetByName (Airbnb)

My methods were looking like this.

[HttpGet("{id}")]
public IEnumerable<ListingsAndReviews> GetById(String id)
{
}

[HttpGet("{name}")]
public IEnumerable<ListingsAndReviews> GetByName(String name) 
{
}

Upvotes: 0

Views: 1812

Answers (2)

Hugo Vrana
Hugo Vrana

Reputation: 303

As you can see, the name of these methods is different, but they have same parameters, which causes issue.

To solve this issue, you have to set new Property "Order" to the HttpGet method attribute.

[HttpGet("id/{id}", Order = 0)]
public IEnumerable<ListingsAndReviews> GetById(String id)
{
}

[HttpGet("name/{name}", Order = 1)]
public IEnumerable<ListingsAndReviews> GetByName(String name) 
{
}

The Order property differentiates between the 2 methods.

The best practice might be adding the order property to every method.

Hope this can help someone, if not, feel free to suggest better solution.

[Edit]

I ended up with following structure for the template

"id/{id}"
"name/{name}"

this forces the route to first set the filtered parameter, then the value.

Following structure is now established

localhost/ListingsAndReviews
localhost/ListingsAndReviews/id/1
localhost/ListingsAndReviews/name/SomeName

Upvotes: 1

Arcord
Arcord

Reputation: 1939

I have to ask : Are you sure the "ID" will not be an integer or a guid or something like that ? If it's the case you can directly use the expected type into the action:

public IEnumerable<ListingsAndReviews> GetById(Guid id)

It's a really a string (as the name) you can use route parameter constraint :

That way you can define what the "ID" will looks like and what the name will looks like.

By example if you know that ID will only have 5 characters max you could do:

[HttpGet("{id:maxlength(5)}")]

I just gave you the mechanism but the specific answer to you issue will depend on : What are the IDs looks like ? (I guess the name can be anything...).

If you cannot differentiate ID and name you shouldn't have 2 endpoints (but maybe in one endpoint you can search once for the ID and once for the name as a fallback).

Upvotes: 0

Related Questions