2012-11-28 14 views
84

ho il difetto percorso in Global.asax:Web API Routing - API/{Controller}/{action}/{id} "disfunzioni" api/{Controller}/{id}

RouteTable.Routes.MapHttpRoute(
     name: "DefaultApi", 
     routeTemplate: "api/{controller}/{id}", 
     defaults: new { id = System.Web.Http.RouteParameter.Optional } 
     ); 

I volevo essere in grado di indirizzare una specifica funzione, così ho creato un altro itinerario:

RouteTable.Routes.MapHttpRoute(
     name: "WithActionApi", 
     routeTemplate: "api/{controller}/{action}/{id}", 
     defaults: new { id = System.Web.Http.RouteParameter.Optional } 
     ); 

quindi, a mio controllo, ho:

public string Get(int id) 
    { 
     return "object of id id"; 
    }   

    [HttpGet] 
    public IEnumerable<string> ByCategoryId(int id) 
    { 
     return new string[] { "byCategory1", "byCategory2" }; 
    } 

Calling .../api/records/bycategoryid/5 mi darà quello che voglio. Tuttavia, chiamando .../api/records/1 mi darà l'errore

Più azioni sono stati trovati che corrispondono alla richiesta: ...

capisco perché questo è - i percorsi solo definiscono quali URL sono validi, ma quando si tratta di corrispondenza delle funzioni, sia Get(int id) sia ByCategoryId(int id) corrispondono a api/{controller}/{id}, che è ciò che confonde il framework.

Cosa devo fare per far funzionare di nuovo la rotta API predefinita e mantenere quella con {action}? Ho pensato di creare un controller diverso denominato RecordByCategoryIdController in modo che corrisponda alla route API predefinita, per la quale richiederei .../api/recordbycategoryid/5. Tuttavia, trovo che sia una soluzione "sporca" (quindi insoddisfacente). Ho cercato delle risposte a questo e nessun tutorial sull'uso di una rotta con {action} menziona anche questo problema.

risposta

95

Il motore del percorso utilizza la stessa sequenza in cui vengono aggiunte regole. Una volta che ottiene la prima regola abbinata, smetterà di controllare altre regole e prenderà questo per cercare controller e azioni.

Quindi, è necessario:

  1. Metti le norme specifiche in vista delle regole generali (come impostazione predefinita), il che significa usare RouteTable.Routes.MapHttpRoute per mappare "WithActionApi" prima, poi "DefaultApi".

  2. rimuovere il parametro defaults: new { id = System.Web.Http.RouteParameter.Optional } della regola "WithActionApi" perché una volta che id è facoltativo, url del tipo "/ api/{part1}/{} part2" non sarà mai va in "DefaultApi".

  3. Aggiungi un'azione denominata al tuo "DefaultApi" per indicare al motore di rotta quale azione inserire. Altrimenti, una volta che hai più di una azione nel tuo controller, il motore non saprà quale usare e lancia "Sono state trovate più azioni che corrispondono alla richiesta: ...". Quindi, per farlo corrispondere al metodo Get, utilizzare uno ActionNameAttribute.

Così il vostro itinerario dovrebbe in questo modo:

// Map this rule first 
RouteTable.Routes.MapRoute(
    "WithActionApi", 
    "api/{controller}/{action}/{id}" 
); 

RouteTable.Routes.MapRoute(
    "DefaultApi", 
    "api/{controller}/{id}", 
    new { action="DefaultAction", id = System.Web.Http.RouteParameter.Optional } 
); 

E il controller:

[ActionName("DefaultAction")] //Map Action and you can name your method with any text 
public string Get(int id) 
{ 
    return "object of id id"; 
}   

[HttpGet] 
public IEnumerable<string> ByCategoryId(int id) 
{ 
    return new string[] { "byCategory1", "byCategory2" }; 
} 
+1

Ho provato il consiglio sopra e tutto funziona come previsto. Grazie mille per questo "segreto". –

+0

Sul punto 2 della tua risposta, se 'id' è opzionale, URL come'/api/{part1}/{part2} 'può ancora andare nella rotta' DefaultApi' se non viene trovata alcuna azione corrispondente per la rotta 'WithActionApi'. Per favore correggimi se sbaglio. – orad

33

È possibile risolvere il problema con l'aiuto di attributo di routing

controller

[Route("api/category/{categoryId}")] 
public IEnumerable<Order> GetCategoryId(int categoryId) { ... } 

URI in jQuery Configurazione percorso

api/category/1 

using System.Web.Http; 

namespace WebApplication 
{ 
    public static class WebApiConfig 
    { 
     public static void Register(HttpConfiguration config) 
     { 
      // Web API routes 
      config.MapHttpAttributeRoutes(); 

      // Other Web API configuration not shown. 
     } 
    } 
} 

e il vostro comportamento di default sta funzionando come predefinita convenzione a base di routing

controller

public string Get(int id) 
    { 
     return "object of id id"; 
    } 

URI in jQuery

/api/records/1 

percorso di configurazione

public static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config) 
    { 
     // Attribute routing. 
     config.MapHttpAttributeRoutes(); 

     // Convention-based routing. 
     config.Routes.MapHttpRoute(
      name: "DefaultApi", 
      routeTemplate: "api/{controller}/{id}", 
      defaults: new { id = RouteParameter.Optional } 
     ); 
    } 
} 

Review articolo per ulteriori informazioni Attribute routing and onvention-based routing here 012.this

+0

dio risposta. ma non possiamo aggiungere per tutti, api/{controller}/{action}/{id} insieme a api/{controller}/{id}? – karim

+0

Il routing degli attributi risolve definitivamente il problema. Un punto importante: prima di Web API 2, i modelli di progetto dell'API Web hanno generato un codice come questo: protetto void Application_Start() {WebApiConfig.Register (GlobalConfiguration.Configuration); } Se il routing degli attributi è abilitato, questo codice genererà un'eccezione. Se si aggiorna un progetto API Web esistente per utilizzare il routing degli attributi, assicurarsi di aggiornare questo codice di configurazione al seguente: protetto void Application_Start() {GlobalConfiguration.Configure (WebApiConfig.Register); } – Deeb