WebApi Several actions were found using GetAll () and GetByIds (int [] ids)

Using the standard route:

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

Using these steps:

 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"; } 

And make the request / api / values, I get this exception:

 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 

I spun the wheels, trying to find a solution around this. I believe that the actions of GetAll and GetByIds are counted somewhat here, but they are not because GetByIds has a different signature. p>

Is there any work for this that does not include adding {action} to the route?

+8
c # asp.net-web-api asp.net-web-api-routing
source share
4 answers

Thanks for putting everyone in. After you select an option, the only way I found this is to combine the GetAll and GetByIds actions and toggle the case length identifiers.

 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"; } } 
+6
source share

We currently do not have support in the box to bind a collection of values ​​coming from Uri. The following is a problem associated with this, as well as an ambiguity problem:

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

Unfortunately, I can’t come up with the work related to the problem of choosing an Action (without the "{action}" itself), even if you solve the problem of binding to the collection using custom parameter binding, as shown below:

 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 { } } 
+2
source share

I would recommend attribute 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"; } 
+2
source share
 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 } ); 
0
source share

All Articles