WebApi Было найдено несколько действий с GetAll() и GetByIds(int[] ids)
Используя стандартный маршрут:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
С помощью этих действий:
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";
}
И сделать запрос в / api / values, я получаю это исключение:
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
Я крутил свои колеса, пытаясь найти решение вокруг этого. Я считаю, что действия GetAll и GetByIds здесь считаются множественными, но это не так, потому что GetByIds имеет разную подпись.
Есть ли способ обойти это, не добавляя {action}
к маршруту?
4 ответа
Благодарность за вклад каждого. После поиска вариантов, единственный способ, который я нашел, - это объединить действия GetAll и GetByIds и переключить регистр на длину идентификаторов.
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";
}
}
Я бы порекомендовал атрибут маршрутизации:
[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";
}
В настоящее время мы не имеем встроенной поддержки для привязки коллекции значений, поступающих из Uri. Ниже приводится вопрос, касающийся этого, а также проблема устранения неоднозначности действий:
http://aspnetwebstack.codeplex.com/workitem/322
К сожалению, я не могу придумать обходной путь, связанный с самой проблемой выбора действия (без '{action}'), даже если вы решаете проблему привязки модели к коллекции, используя привязку пользовательского параметра, как показано ниже:
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
{
}
}
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 }
);