7

I have a single controller with two actions. Each action takes a GUID parameter. My request URL looks like this: http://baseURL/api/v1.0/loadfactors/search?cedentId=5FF7165C-7575-EA11-AA4D-949554C02DE1

This is how my actions look like:

    [HttpGet("search")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public async Task<List<LoadFactorResource>> GetByLobSettingsId([FromQuery]Guid lobSettingsId)
    {
        return await _service.GetByLobSettingsId(lobSettingsId);
    }

    [HttpGet,Route("search")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public async Task<List<LoadFactorResource>> GetByAccountId([FromQuery]Guid cedentId)
    {
        return await _service.GetByCedentId(cedentId);
    }

Now when I make a request, this is the error I get:

An unhandled exception occurred while processing the request. AmbiguousMatchException: The request matched multiple endpoints. Matches:

LoadFactorsController.GetByLobSettingsId (Api) LoadFactorsController.GetByAccountId (Api)

It seems it is finding multiple actions and not identifying action based on the query parameter. How do I make so it matches based on the parameter?

Thanks.

4
  • 1
    The method signatures are identical (same route, same GUID parameter), so there is nothing to differentiate one from the other. By default the name of the query parameter isn't taken into account. Try the IActionConstraint response in this similar question: stackoverflow.com/questions/46477959/… Commented Apr 9, 2020 at 14:42
  • 1
    Can you change your api to [HttpGet("search/LobSettingsId/{lobSettingsId:Guid}")] and [HttpGet("search/AccountId/{accountId:Guid}")] then it is clear what each does and should avoid the error Commented Apr 9, 2020 at 23:40
  • @Rosco No I cannot. I thought about it, but the service is already consumed by the clients and I just need to add another query string parameter. Commented Apr 10, 2020 at 22:42
  • @BryanLewis Thanks that did the trick! Commented Apr 10, 2020 at 22:42

1 Answer 1

9

An unhandled exception occurred while processing the request. AmbiguousMatchException: The request matched multiple endpoints.

As error indicates that the request matched multiple actions resulting in ambiguity.

To fix it and achieve your requirement, you can try following approaches:

Approach 1: merge these two action as one action and dynamically check query string value that client passed.

[HttpGet("search")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<List<LoadFactorResource>> GetByLobSettingsId([FromQuery]Guid lobSettingsId, [FromQuery]Guid cedentId)
{
    if (lobSettingsId != Guid.Empty)
    {
        return await _service.GetByLobSettingsId(lobSettingsId);
    }

    return await _service.GetByCedentId(cedentId);
}

Approach 2: implement a custom ActionMethodSelectorAttribute to enable or disable an action for a given request based on passed query string, like below.

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class CheckQueryStringAttribute : ActionMethodSelectorAttribute
{
    public string QueryStringName { get; set; }
    public bool CanPass { get; set; }
    public CheckQueryStringAttribute(string qname, bool canpass)
    {
        QueryStringName = qname;
        CanPass = canpass;
    }

    public override bool IsValidForRequest(RouteContext routeContext, ActionDescriptor action)
    {
        StringValues value;

        routeContext.HttpContext.Request.Query.TryGetValue(QueryStringName, out value);

        if (CanPass)
        {
            return !StringValues.IsNullOrEmpty(value);
        }

        return StringValues.IsNullOrEmpty(value);
    }
}

Apply it to actions

[HttpGet("search")]
[CheckQueryStringAttribute("lobSettingsId",true)]
[CheckQueryStringAttribute("cedentId", false)]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<List<LoadFactorResource>> GetByLobSettingsId([FromQuery]Guid lobSettingsId)
{  
    return await _service.GetByCedentId(cedentId);                
}

[HttpGet, Route("search")]
[CheckQueryStringAttribute("lobSettingsId", false)]
[CheckQueryStringAttribute("cedentId", true)]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<List<LoadFactorResource>> GetByAccountId([FromQuery]Guid cedentId)
{
    return await _service.GetByCedentId(cedentId);
}
Sign up to request clarification or add additional context in comments.

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.