ASP.NET Core – The request matched multiple endpoints

Problem

When you send a request to an endpoint, you get the following error response:

500 - Internal Server Error

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

Controllers.WeatherForecastController.GetByAreaCode
Controllers.WeatherForecastController.GetByCityNameCode language: plaintext (plaintext)

Note: If you’re using Swagger, you may see this in the UI as a generic error: “Failed to load API definition … response status is 500.” If you look in the ASP.NET Core Web Server output in Visual Studio, you can see the underlying error: “SwaggerGeneratorException: Conflicting method/path combination.”

This problem is caused by having multiple controller methods with the same HTTP method / path combination (even if the path parameters are different!). Since there are multiple candidates, the framework can’t figure out which controller method to call, hence it throws the AmbiguousMatchException. Here’s an example of ambiguous controller methods:

[HttpGet("{areaCode}")]
public WeatherForecast GetByAreaCode(int areaCode)
{
	//return weather for area code
}
[HttpGet("{cityName}")]
public WeatherForecast GetByCityName(string cityName)
{
	//return weather for city name
}
Code language: C# (cs)

The solution is to disambiguate the paths. The two main options for doing that are 1) use route constraints or 2) change the paths to be different.

Solution

Option 1 – Use route constraints

Here’s an example of using two route constraints to specify the type of the path parameters:

[HttpGet("{areaCode:int}")]
public WeatherForecast GetByAreaCode(int areaCode)
{
	//return weather for area code
}
[HttpGet("{cityName:alpha}")]
public WeatherForecast GetByCityName(string cityName)
{
	//return weather for city name
}
Code language: C# (cs)

This disambiguates the GET /weatherforecast/<path parameter> request in the following way:

  • If the path parameter is an integer, {areaCode:int} makes it to route to GetByAreaCode(int areaCode).
    • Ex: GET /weatherforecast/313 routes to GetByAreaCode(313).
  • If the path parameter is all alphabetic characters, {cityName:alpha} makes it to route to GetByCityName(string cityName).
    • Ex: GET /weatherforecast/Detroit routes to GetByCityName(“Detroit”)

Go here to see the full list of route constraints available: ASP.NET Core route constraints.

Option 2 – Change the paths to be different

The other option is to change the paths so they’re different. Consider the following two controller methods:

[HttpGet]
public IEnumerable<WeatherForecast> GetAll()
{
	//get weather for everywhere
}
[HttpGet]
public WeatherForecast GetWithQuery([FromQuery]string cityName)
{
	//get weather for specific city
}
Code language: C# (cs)

These both map to GET /weatherforecast. Why? Because unlike path parameters, query string parameters don’t change the path for routing purposes. To disambiguate, change one or more of the paths explicitly:

[HttpGet("all")]
public IEnumerable<WeatherForecast> GetAll()
{
	//get weather for everywhere
}
[HttpGet("search")]
public WeatherForecast GetWithQuery([FromQuery]string cityName)
{
	//get weather for specific city
}
Code language: C# (cs)

This now handles requests such as the following:

  • GET /weatherforecast/all
  • GET /weatherforecast/search?cityName=Detroit

Note: Another option here is to combine these two methods into a single method, and treat the query string parameter like an optional parameter (only use it if it’s not null).

Leave a Comment