0

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) 
{
}
3
  • Put yourself in the url router's shoes and ask yourself, which method should the router invoke for a url like site.com/ListingsAndReviews/gibberish-string? Your router dont know whether gibberish-string is a id or a name. So help it find a match, change your url template to something different for each method. Commented Mar 9, 2021 at 16:52
  • are you sure id is a string? Commented Mar 9, 2021 at 17:55
  • @Nonik the id is technically an ObjectId, but i can enter the Id only as a string, then convert it to ObjectId. The queries are done with ObjectId. I will probably change it, once i build an front end... Commented Mar 9, 2021 at 18:18

2 Answers 2

1

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
Sign up to request clarification or add additional context in comments.

1 Comment

How does this answer resolve your problem? You changed routes themselves, {id} to id/{id} and {name} to name/{name}. Do you really need to use Order here?
0

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).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.