可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Using the standard route:
config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } );
With these actions:
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 a request to /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've been spinning my wheels trying to find a solution around this. It's my belief that the GetAll and GetByIds actions are considered Multiple here, but they aren't because the GetByIds has a different signature.
Is there a work around for this that doesn't involve adding {action}
to the route?
回答1:
Thanks for the input everyone. After kicking options around, the only way I found to do this, is to combine the GetAll and GetByIds action and switch case the length of ids.
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"; } }
回答2:
We currently do not have out of box support for binding collection of values coming from Uri. Following is the issue regarding that and also the action disambiguation problem:
http://aspnetwebstack.codeplex.com/workitem/322
Unfortunately, i cannot think of a work around related to the Action selection problem(without the '{action}') itself even though you solve the problem of modelbinding to collection using a custom parameter binding like 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 { } }
回答3:
I'd 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"; }
回答4:
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 } );