WebApi Было обнаружено несколько действий с GetAll() и GetByIds(int[] id)

По стандартному маршруту:

        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} к маршруту?


person Levitikon    schedule 15.04.2013    source источник
comment
Не могли бы вы опубликовать WebApi Route.Config?   -  person Fals    schedule 15.04.2013
comment
Добавлен @Fals, это стандартные биты   -  person Levitikon    schedule 15.04.2013


Ответы (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";
        }
    }
person Levitikon    schedule 18.04.2013
comment
Это также единственное решение, которое я нашел для Web API 2. Однако в моем случае я должен проверять ids == null, а не ids.Length == 0. Я не уверен, было ли это изменение, внесенное в Web API 2, но если я вызову api/values без каких-либо значений для ids, массив будет null, а не пустым. - person Nick; 12.09.2014

В настоящее время у нас нет встроенной поддержки для привязки коллекции значений, поступающих из 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
    {
    }
}
person Kiran Challa    schedule 15.04.2013

Я бы рекомендовал маршрутизацию атрибутов:

[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";
    }
person Tom Dunn    schedule 11.07.2014

person    schedule
comment
Это взлом. Почему вы используете WebAPI, если вам неинтересно создавать ресурсный API? Помещение действия в URL-адрес разрушает ортогональность глагола и URL-адреса, которую должен иметь HTTP/REST; вы могли бы просто использовать MVC, который создан для такого рода RPC. - person Keith Pinson; 11.03.2014
comment
Кроме того, вам действительно не следует публиковать блоки кода без какого-либо пояснительного текста. - person Keith Pinson; 11.03.2014