2013-01-21 12 views
8

Sembra che sia disponibile una logica predefinita per l'API Web per utilizzare il verbo HTTP come nome dell'azione se non è stata fornita alcuna azione nell'URL. Per esempio, io ho questo percorso:Come modificare le rotte API Web predefinite del framework?

 config.Routes.MapHttpRoute(
      name: "DefaultApiController", 
      routeTemplate: "api/{controller}" 
     ); 

E qui sono le mie azioni:

public IEnumerable<Conference> Get() 
    { 
     ... 
    } 

    [ActionName("current")] 
    public IEnumerable<Conference> GetCurrent() 
    { 
     ... 
    } 

Quando vado a ~/Conferenze con un verbo GET, che vi porterà al "GET() "azione. Se usi il verbo POST, ti porterà all'azione "Post ([FromBody] Conference value") ... e così via. V'è un conflitto anche se quando si tenta di andare a ~/Conferenze/GetCurrent (anche se ho [ActionName ("corrente")] in alto):

Più azioni sono stati trovati che corrispondono alla richiesta: sistema .Collections.Generic.IEnumerable 1[MyApp.Models.Conference] Get() on type MyApp.Api.ConferencesController System.Collections.Generic.IEnumerable 1 [MyApp.Models.Conference] GetCurrent() su tipo MyApp.Api.ConferencesController

Ciò implica il quadro utilizza StartsWith anziché uguale a determinare un'azione predefinita. Inoltre, sta ignorando l'attributo ActionName durante l'abbinamento di verb to action.

La mia domanda è: come faccio a fare in modo che l'azione predefinita del framework corrisponda esattamente al verbo, invece di usare la logica di StartsWith? Un verbo GET deve corrispondere solo a un'azione Get(), non a Get(), GetCurrent() GetPast(), ecc. (Specialmente quando si ignora l'attributo ActionName).

EDIT Per semplicità, ho mostrato solo uno dei miei percorsi sopra. Penso che possa essere d'aiuto se mostro tutti i miei percorsi che sono ancora in fase di bozza. Sto cercando di ottenere un REST API completamente funzionante, pur lasciando spazio per l'aggiunta di mie azioni personalizzate:

public static void Register(HttpConfiguration config) 
    { 
     config.Routes.MapHttpRoute(
      name: "DefaultApiControllerActionId", 
      routeTemplate: "api/{controller}/{action}/{id}", 
      defaults: null, 
      constraints: new { action = @"^[a-zA-Z]+$", id = @"^\d+$" } // action must start with character 
     ); 

     config.Routes.MapHttpRoute(
      name: "DefaultApiControllerActionName", 
      routeTemplate: "api/{controller}/{action}/{name}", 
      defaults: null, 
      constraints: new { action = @"^[a-zA-Z]+$", name = @"^[a-zA-Z]+$" } // action and name must start with character 
     ); 

     config.Routes.MapHttpRoute(
      name: "DefaultApiControllerId", 
      routeTemplate: "api/{controller}/{id}", 
      defaults: null, 
      constraints: new { id = @"^\d+$" } // id must be all digits 
     ); 

     config.Routes.MapHttpRoute(
      name: "DefaultApiControllerAction", 
      routeTemplate: "api/{controller}/{action}", 
      defaults: null, 
      constraints: new { action = @"^[a-zA-Z]+$" } // action must start with character 
     ); 

     config.Routes.MapHttpRoute(
      name: "DefaultApiController", 
      routeTemplate: "api/{controller}" 
     ); 

UPDATE Sembra che l'aggiunta di vincoli verbo HTTP aiutato:

 config.Routes.MapHttpRoute(
      name: "DefaultApiControllerGet", 
      routeTemplate: "api/{controller}", 
      defaults: new { action = "Get" }, 
      constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) } 
     ); 

     config.Routes.MapHttpRoute(
      name: "DefaultApiControllerPost", 
      routeTemplate: "api/{controller}", 
      defaults: new { action = "Post" }, 
      constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Post) } 
     ); 

     config.Routes.MapHttpRoute(
      name: "DefaultApiControllerPut", 
      routeTemplate: "api/{controller}", 
      defaults: new { action = "Put" }, 
      constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Put) } 
     ); 

     config.Routes.MapHttpRoute(
      name: "DefaultApiControllerDelete", 
      routeTemplate: "api/{controller}", 
      defaults: new { action = "Delete" }, 
      constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Delete) } 
     ); 

risposta

7

EDIT : Dato che hai apportato una grande modifica alla domanda, ho bisogno di cambiare la risposta:

In breve - questo non funzionerà mai fuori dalla scatola con Web API, perché sarà di default inviare l'azione:

  1. in base a nome dell'azione se {azione} fa parte dei dati del percorso
  2. basano sul verbo HTTP

Tuttavia, questi due approcci non può essere mescolato in un singolo controller, quindi non sarà possibile inviare azioni utilizzando entrambi gli approcci da un singolo controller (che è ciò che si sta tentando di fare).

avete tre modi per risolvere questo:

  1. rielaborare le risorse, in modo da avere quelle separate per azione nome dispacciamento e disptaching verbo-based (che è ben lungi dall'essere ideale)

  2. registra manualmente i percorsi per tutti i percorsi nidificati. In questo modo continui a spedire tramite verbo HTTP, ma il routing indica chiaramente un'azione specifica. Potresti usare qualcosa come AttributeRouting (https://github.com/mccalltd/AttributeRouting) per semplificare questo. Ovviamente si finisce con - in modo efficace - un percorso per azione

  3. Implementare un nuovo IActionSelector che consentirebbe di combinare sia il dispacciamento basato su verbo sia il nome basato su azione in un singolo controller. Questa è la soluzione più "di basso livello", ma sembra esattamente come qualcosa che vuoi fare. Ho pubblicato un walkthrough la scorsa settimana - http://www.strathweb.com/2013/01/magical-web-api-action-selector-http-verb-and-action-name-dispatching-in-a-single-controller/

+0

Per un API REST, avrei ancora bisogno di ottenere ~/Conferenze ancora lavorando però – Basem

+0

edit: ok ora che hai postato tutte le rotte, il quadro è molto più chiaro;) –

+0

Articolo fantastico, grazie! Anche AttributeRouting sembra promettente, ma sembra che le prestazioni dell'API Web e le funzionalità di memorizzazione nella cache non siano sfruttate. – Basem

Problemi correlati