Controller action throws AmbiguousMatchException at first, then NotImplementedException when one [sic] is removed

Viewed 61

I'm porting an older API project from .NET Framework 4.7.2 to .NET 5, and I would like to keep the same API signatures as the existing project to preserve API compatibility. That's proving troublesome. (For this question, ignore that context; I'm just giving it to say why I don't want to change the URL routes as Zhi Lv has suggested.)

One of the .NET 5 project's controllers has an action with this signature:

[HttpGet]
[Route("{processedId}")] 
// I had also tried [Route("{processedId:int}")] -- EDIT: but missed that there was a different exception when I did. 
public async Task<TypedActionResult<Question>> GetQuestionByProcessedId(int processedId)

When I attempt to access using this URL:

https://localhost:12345/api/questions/2

... I receive the following:

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

My.Namespace.Api.Controllers.MyController.GetQuestionsForFolder (QuestionBuilder.Api)
My.Namespace.Api.Controllers.MyController.GetQuestionByProcessedId (QuestionBuilder.Api)

That other controller action mentioned in that error has this signature:

[HttpGet]
[Route("{folderId=folderId:Guid}")]
public async Task<TypedActionResult<IEnumerable<Question>>> GetQuestionsForFolder(Guid folderId)

If I comment out the offending, "ambiguous" match and make a new call, I receive...

System.NotImplementedException: The method or operation is not implemented.

The same error appears if I flip the experiment by commenting out the intended endpoint, GetQuestionByProcessedId, and leave only GetQuestionsForFolder.

Note that I ­can successfully access the GetQuestionsForFolder endpoint (when it's not commented out, natch) using the following URL:

https://localhost:12345/api/questions/?folderId=87654321-1234-1234-1234-123456789012


Question

These errors seem to be in conflict. In one case, I have too many endpoints ready to serve the GET request. When I remove one of the two, I then have none.

How can I make the URL find the right controller action, and why is it seeing two and then seeing none?

To be overly clear, I am aware that I could likely merge the endpoints to resolve this issue. My question is why I have two endpoints grabbing the request and then, when one is removed, none.

1 Answers

The request matched multiple endpoints

To solve the above error, you could set the route constraint for each endpoint.

For example:

    [HttpGet]
    [Route("{processedId:int}")] // the parameter is int type, allow the request with int parameter
    public async Task<IActionResult> GetQuestionByProcessedId(int processedId)
    {
        return Ok("value: " + processedId.ToString());
    }

    [HttpGet]
    [Route("{folderId=folderId:Guid}")] //the parameter is guid type, allow the request with guid parameter
    public async Task<IActionResult> GetQuestionsForFolder(Guid folderId)
    {
        return Ok("value: " + folderId.ToString());
    }

The result as below:

enter image description here

Besides, you can also add the action name in the route/request url, code as below:

    [HttpGet]
    [Route("getQuestionByProcessedId/{processedId}")] // the parameter is int type
    public async Task<IActionResult> GetQuestionByProcessedId(int processedId)
    {
        return Ok("value: " + processedId.ToString());
    }

    [HttpGet]
    [Route("getQuestionsForFolder/{folderId=folderId:Guid}")] //the paramer is guid type
    public async Task<IActionResult> GetQuestionsForFolder(Guid folderId)
    {
        return Ok("value: " + folderId.ToString());
    }

Then the request URL like this:

https://localhost:44310/api/todo/getQuestionsForFolder/87654321-1234-1234-1234-123456789012

https://localhost:44310/api/todo/getQuestionByProcessedId/2

the output as below:

enter image description here

Related