8

Utilizzando il percorso standard:WebAPI Più azioni sono state trovate con GetAll() e GetByIds (int [] IDS)

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

Con queste azioni:

public class ValuesController : ApiController 
{ 
    // GET api/values 
    public string GetAll() 
    { 
     return "all"; 
    } 

    // GET api/values/5 
    public string GetById(int id) 
    { 
     return "single"; 
    } 

    // GET api/values?ids=1&ids=2 
    public string GetByIds([FromUri] int[] ids) 
    { 
     return "multiple"; 
    } 

e fare una richiesta per /API/valori, ottengo questa eccezione:

Multiple actions were found that match the request: 
System.String GetAll() on type MvcApplication4.Controllers.ValuesController 
System.String GetByIds(Int32[]) on type MvcApplication4.Controllers.ValuesController 

Sto filando le ruote cercando di f ind soluzione a questo. Sono convinto che le azioni GetAll e GetByIds siano considerate Più qui, ma non lo sono perché GetByIds ha una firma diversa.

C'è una soluzione per questo che non comporta l'aggiunta di {action} al percorso?

+0

Potrebbe pubblicare il WebAPI Route.Config? – Fals

+0

Aggiunto @Fals, sono i bit standard – Levitikon

risposta

6

Grazie per l'input tutti. Dopo aver calciato le opzioni in giro, l'unico modo in cui ho trovato di farlo è combinare l'azione GetAll e GetByIds e passare il caso alla lunghezza degli id.

public class ValuesController : ApiController 
{ 
    // GET api/values/5 
    public string GetById(int id) 
    { 
     return "single"; 
    } 

    // GET api/values 
    // GET api/values?ids=1&ids=2 
    public string GetByIds([FromUri] int[] ids) 
    { 
     switch (ids.Length) 
     { 
      case 0: 
       return "all"; 

      default: 
       return "multiple"; 
     } 
    } 
+0

Questa è anche l'unica soluzione che ho trovato per Web API 2. Tuttavia, nel mio caso devo controllare 'ids == null' piuttosto che' ids.Length == 0'. Non sono sicuro che si trattasse di una modifica apportata in Web API 2, ma se chiamo 'api/values' senza alcun valore per' ids', l'array è 'null' anziché vuoto. – Nick

2

Al momento non è disponibile il supporto per la raccolta di valori vincolanti da Uri. In seguito è il problema per quanto riguarda questo e anche il problema dell'azione disambiguazione:

http://aspnetwebstack.codeplex.com/workitem/322

Purtroppo, non riesco a pensare ad un modo per aggirare relativa al problema di selezione di azione (senza il '{azione}') in sé, anche se si risolvere il problema di modelbinding per la raccolta utilizzando un legame di parametri personalizzato come di seguito:

public string GetByIds(int[] ids) 
    { 
     return "multiple"; 
    } 
------------------------ 

config.ParameterBindingRules.Insert(0, typeof(int[]), (paramDesc) => new SampleParameterBinding(paramDesc)); 

------------------------- 

public class SampleParameterBinding : HttpParameterBinding 
{ 
    public SampleParameterBinding(HttpParameterDescriptor desc) 
     : base(desc) 
    { 
    } 

    public override bool WillReadBody 
    { 
     get 
     { 
      return false; 
     } 
    } 

    public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken) 
    { 
     HttpRequestMessage currentRequest = actionContext.Request; 

     NameValueCollection nvc = currentRequest.RequestUri.ParseQueryString(); 

     //TODO: ERROR CHECKS 
     int[] ids = nvc["ids"].Split(',').Select(str => Int32.Parse(str)).ToArray(); 

     // Set the binding result here 
     SetValue(actionContext, ids); 

     // now, we can return a completed task with no result 
     TaskCompletionSource<AsyncVoid> tcs = new TaskCompletionSource<AsyncVoid>(); 
     tcs.SetResult(default(AsyncVoid)); 
     return tcs.Task; 
    } 

    private struct AsyncVoid 
    { 
    } 
} 
0
public static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config) 
    { 
     config.Routes.MapHttpRoute(
      name: "DefaultApi", 
      routeTemplate: "api/{controller}/{action}/{id}", 
      defaults: new { id = RouteParameter.Optional } 
     ); 
+1

Questo è un hack. Perché stai utilizzando WebAPI se non sei interessante nella creazione di un'API di risorse? Mettendo l'azione nell'URL si distrugge l'ortogonalità di verbo e URL che HTTP/REST deve avere; potresti anche usare MVC, che è costruito per questo tipo di RPC. –

+0

Inoltre, non dovresti pubblicare blocchi di codice senza una sorta di testo esplicativo. –

2

mi consiglia attributo di routing:

[RoutePrefix("api")] 
public class ValuesController : ApiController 
{ 
    // GET api/values 
    // GET api/values?ids=1&ids=2 
    [Route("values")] 
    public string GetCollection([FromUri] IList<int> ids) 
    { 
     if (ids == null) 
     { 
      return "all"; 
     } 
     return "multiple"; 
    } 

    // GET api/values/5 
    [Route("values/{id:int}")] 
    public string GetById(int id) 
    { 
     return "single"; 
    } 
Problemi correlati