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.
[FromQuery] - Gets values from the query string. [FromRoute] - Gets values from route data. [FromForm] - Gets values from posted form fields. [FromBody] - Gets values from the request body.
Using [FromUri] To force Web API to read a complex type from the URI, add the [FromUri] attribute to the parameter. The following example defines a GeoPoint type, along with a controller method that gets the GeoPoint from the URI.
A Get does not send the body of the form, it only requests a URL. Use a <form> in your view and post it to your controller method, which needs to be decorated with HttpPost.
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With