WebApi使用GetAll()和GetByIds(int [] ids)找到多个操作

时间:2013-04-15 17:57:44

标签: c# asp.net-web-api asp.net-web-api-routing parameterbinding

使用标准路线:

        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 个答案:

答案 0 :(得分:6)

感谢大家的投入。在踢开选项之后,我发现这样做的唯一方法是组合GetAll和GetByIds操作并切换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";
        }
    }

答案 1 :(得分:2)

我们目前没有对来自Uri的绑定值集合的开箱即用支持。以下是有关此问题以及消除歧义问题的问题:

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

不幸的是,即使你使用如下的自定义参数绑定解决了模型绑定到集合的问题,我也无法想到与Action选择问题(没有'{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
    {
    }
}

答案 2 :(得分:2)

我建议使用属性路由:

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

答案 3 :(得分: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 }
        );