ASP.NET Core:la richiesta corrispondeva a più endpoint

ASP.NET Core:la richiesta corrispondeva a più endpoint

Problema

Quando invii una richiesta a un endpoint, ricevi la seguente risposta di errore:

500 - Internal Server Error

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

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

Nota:se stai utilizzando Swagger, potresti visualizzare questo messaggio nell'interfaccia utente come un errore generico:"Impossibile caricare la definizione dell'API... lo stato della risposta è 500". Se guardi nell'output del server Web ASP.NET Core in Visual Studio, puoi visualizzare l'errore sottostante:"SwaggerGeneratorException:combinazione metodo/percorso in conflitto".

Questo problema è causato dalla presenza di più metodi controller con la stessa combinazione metodo HTTP/percorso (anche se i parametri del percorso sono diversi!). Poiché ci sono più candidati, il framework non riesce a capire quale metodo controller chiamare, quindi genera AmbiguousMatchException. Ecco un esempio di metodi di controllo ambigui:

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

La soluzione è disambiguare i percorsi. Le due opzioni principali per farlo sono 1) utilizzare i vincoli di percorso o 2) modificare i percorsi in modo che siano diversi.

Soluzione

Opzione 1 – Usa i vincoli di percorso

Ecco un esempio di utilizzo di due vincoli di percorso per specificare il tipo di parametri del percorso:

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

Questo disambigua la richiesta GET /weatherforecast/ nel modo seguente:

  • Se il parametro path è un numero intero, {areaCode:int} lo fa instradare a GetByAreaCode(int areaCode).
    • Es:GET /weatherforecast/313 rotte verso GetByAreaCode(313).
  • Se il parametro path è composto da tutti i caratteri alfabetici, {cityName:alpha} lo fa instradare a GetByCityName(string cityName).
    • Es:GET /weatherforecast/Detroit rotte verso GetByCityName ("Detroit")

Vai qui per vedere l'elenco completo dei vincoli di percorso disponibili:Vincoli di percorso di ASP.NET Core.

Opzione 2:cambia i percorsi in modo che siano diversi

L'altra opzione è cambiare i percorsi in modo che siano diversi. Considera i seguenti due metodi di controllo:

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

Entrambi mappano su GET /weatherforecast. Come mai? Perché a differenza dei parametri di percorso, i parametri della stringa di query non modificano il percorso ai fini del routing. Per disambiguare, cambia esplicitamente uno o più percorsi:

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

Questo ora gestisce richieste come le seguenti:

  • OTTIENI /meteo/tutti
  • GET /weatherforecast/search?cityName=Detroit

Nota:un'altra opzione qui consiste nel combinare questi due metodi in un unico metodo e trattare il parametro della stringa di query come un parametro facoltativo (usarlo solo se non è null).