In che modo ASP.NET Web.api gestisce due metodi con nomi che iniziano con GET?

Sto guardando il seguente tutorial di Microsoft. Come da questo tutorial,

Nel primo esempio, “prodotti” corrisponde al controller denominato ProductsController. La richiesta è una richiesta GET, quindi il framework cerca un metodo su ProductsController il cui nome inizia con “Get …”. Inoltre, l’URI non contiene il segmento opzionale {id}, quindi il framework cerca un metodo senza parametri. Il metodo ProductsController :: GetAllProducts soddisfa tutti questi requisiti.

Cosa succede se ci sono due metodi come GetAllProducts () e GetSoldProducts ()? Entrambi non hanno parametri.

La tua prima esercitazione sull’API Web

Supponendo che si stiano utilizzando i percorsi predefiniti, la risposta breve è: verrà chiamato il metodo definito per primo (nella parte superiore) della class. l’altro metodo è inaccessibile.

NOTA: la beta si è comportata come sopra per “abbinare più metodi” – la versione RC & Release è un po ‘più OCD. Genera un errore se ci sono più potenziali corrispondenze. Questo cambiamento rimuove la confusione di più corrispondenze ambigue. Allo stesso tempo, riduce la nostra capacità di combinare interfacce di stile REST e RPC nello stesso controller, basandosi sull’ordine e sui percorsi sovrapposti.

Rubando liberamente da un altro post che ho scritto sull’argomento :

Semantica di corrispondenza WebAPI

La semantica corrispondente utilizzata da WebAPI è abbastanza semplice.

  1. Corrisponde al nome dell’azione con il verbo (verb = get? Cerca il metodo che inizia con “get”)
  2. se viene passato un parametro, l’api cerca un’azione con un parametro

Quindi nell’esempio di codice una richiesta GET senza un parametro corrisponde alla funzione Get*( ) senza parametri. Un Get contenente e ID cerca un Get***(int id) .

Esempi

Mentre la semantica corrispondente è semplice, crea una certa confusione per gli sviluppatori MVC (beh, almeno questo sviluppatore). Vediamo alcuni esempi:

Nomi dispari : il metodo get può essere denominato qualsiasi cosa, purché inizi con “get”. Quindi, nel caso di un controller di widget, è ansible GetStrawberry() nome alle funzioni GetStrawberry() e verrà comunque associato. Pensa alla corrispondenza come qualcosa del tipo: methodname.StartsWith("Get")

Metodi di corrispondenza multipla – Cosa succede se hai due metodi Get senza parametri? GetStrawberry() e GetOrange() . Come meglio posso dire, la funzione definita per prima (parte superiore del file) nel tuo codice vince … strano. Questo ha l’effetto collaterale di rendere alcuni metodi nel tuo controller irraggiungibili (almeno con le rotte predefinite) …. straniero.

AGGIORNARE

@WinFXGuy – Questo è stato un po ‘lungo per inserire un commento, ma …

Non saltare alle conclusioni! Ho cercato di rispondere alla domanda che hai posto, ma questa è solo metà della storia. C’è molto che puoi fare per modificare il comportamento predefinito.

Innanzitutto , WebAPI supporta gran parte delle specifiche di oData . Se bolla un IQueryable fino al controller, i parametri di data o sono automaticamente integrati con l’object query. Prende parametri come $filter , $top e $skip . Quindi nel tuo caso puoi scrivere un metodo e passare qualcosa come $filter=sale_date neq null .

Inoltre, è ansible applicare l’attributo [ResultLimit] per impedire alle persone di chiedere 15 miliardi di record.

In secondo luogo è ansible modificare i percorsi. Le rotte predefinite puntano a un’API RESTful, in cui generalmente hai 1 controllore per entity framework. Puoi cambiare i percorsi e renderlo stile RPC.

Se si guarda il mio post collegato, spiego come ho mantenuto il bind di route predefinito, aggiunto “sottocartelle” e ho anche permesso chiamate di metodo aggiuntive per gli scenari in cui avevo bisogno di GetAllProducts() e GetSoldProducts() .

Esistono due possibili soluzioni a questo problema specifico:

  1. Alterare MapHttpRoute per richiedere di specificare il nome dell’azione. (Sto usando la syntax di self-hosting):

      config.Routes.MapHttpRoute( "API Route 1", "api/{controller}/{action}"); config.Routes.MapHttpRoute( "API Route 2", "api/{action}", new { controller = "products" }); 

    Quindi il tuo client http chiamerebbe:

    api/products/GetAllProducts OR api/GetAllProducts api/products/GetSoldProducts OR api/GetSoldProducts

    Vedi: http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

  2. Inserire ciascun metodo in un controller separato (ProductsController, SoldProductsController). Quindi chiameresti api/products e api/soldproducts per ottenere i tuoi risultati.


Argomento correlato … nella situazione in cui si dispone di più azioni Ottieni che hanno un singolo argomento primitivo dello stesso tipo, l’API Web ASP.NET esaminerà il nome dell’argomento per risolvere l’azione sovraccaricata da chiamare.

Ad esempio, se hai due azioni:

 GetProductByName(string name) GetProductByCategory(string category) 

il tuo client http può chiamare

 api/products?name=hammer api/products?category=toys 

e il motore di routing chiamerà l’azione corretta.

Aggiunta di una risposta per riflettere che l’ultima versione dell’API Web supporta l’attributo [Route] modo nativo

 [Route("api/products")] public IEnumerable GetAllProducts(){} [Route("api/products/sold")] public IEnumerable GetSoldProducts(){}