【问题标题】:Webapi Routing with Integer array and Actions带有整数数组和操作的 Webapi 路由
【发布时间】:2014-11-21 00:58:56
【问题描述】:

这个问题把我逼疯了。

我有一个使用自定义 ModelBinder 获取 ID 数组的 get 方法(我可以调用 http://xckvjl.com/api/results/1,23,34,)

我想介绍 Gets on action。 (这样我就可以打电话给http://alskjdfasl.com/api/results/latest

我有以下 web api 路由。

config.Routes.MapHttpRoute("DefaultApi", "{controller}/{id}", new { id = RouteParameter.Optional });

config.Routes.MapHttpRoute("ApiWithAction", "{controller}/{action}");

我已经尝试过(请注意这里我使用的是我的自定义模型绑定器)

config.Routes.MapHttpRoute("DefaultApi", "{controller}/{id}", new { id = RouteParameter.Optional }, new {id = @"\d+" });

您可以使用此示例重现此错误:

public class TestController: ApiController {

          [HttpGet]
           public virtual IHttpActionResult Get([ModelBinder(typeof(CommaDelimitedCollectionModelBinder))]IEnumerable<int> id = null )
        { }

          [HttpGet]
           public virtual IHttpActionResult Latest( )
        { }

}

 public class CommaDelimitedCollectionModelBinder : IModelBinder
    {
        public bool BindModel(HttpActionContext actionContext,
            ModelBindingContext bindingContext)
        {
            var key = bindingContext.ModelName;
            var val = bindingContext.ValueProvider.GetValue(key);

            if (val == null)
            {
                return false;
            }

            var s = val.AttemptedValue;
            if (s != null && s.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Length > 0)
            {
                var array = s.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select( n=>Convert.ToInt32(n)).ToArray();
                Type type = bindingContext.ModelType.GetGenericArguments().First();

                var typeValue = Array.CreateInstance(type, array.Length);
                array.CopyTo(typeValue, 0);

                bindingContext.Model = array;
            }
            else
            {
                bindingContext.Model = new[] { s };
            }

            return true;
        }
    }

如果我写成:

[HttpGet]
[Route("Tests/latest")]
 public virtual IHttpActionResult Latest( )
        { }

它有效。但是,我想要全局级路由。否则对于每一个动作,我都必须写相同的。

请指教。

【问题讨论】:

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


    【解决方案1】:

    所以这是两难的:

    有了这个路由定义:

    config.Routes.MapHttpRoute("DefaultApi", "{controller}/{id}", new { id = RouteParameter.Optional });
    

    当你调用http://alskjdfasl.com/api/results/latest时,latest变成id的值,这显然会抛出错误,因为字符串无法转换为int数组。

    添加此路由定义

    config.Routes.MapHttpRoute("ApiWithAction", "{controller}/{action}"); 
    

    将无济于事,因为现在您要么必须处理订单,要么为您的其他操作定义路由,这些操作现在因此被屏蔽。

    没有在单个级别声明路由,唯一的其他选择是使模板不同或创建自己的理解数组的路由约束。

    我会先试一试:

    config.Routes.MapHttpRoute("ApiWithAction", "{controller}/{action}/{id}", new { id = RouteParameter.Optional });
    
    // or if all your methods are called latest
    
    config.Routes.MapHttpRoute("ApiWithAction", "{controller}/latest");
    

    如果没有任何效果,我会说使用属性路由。它们更干净。

    【讨论】:

    • 如果我像你建议的那样翻转它也会抛出多条路线异常。 local/api/users/1 如果 1 是动作名称,这里会变得很困惑......所以我可以为 ID 数组设置约束吗?怎么样?
    • 我想进一步了解 - ApiWithAction 路由的目的是什么?这是您在进行故障排除时正在尝试的事情吗?另外,您可以尝试使用 int[] 代替 IEnumerable 吗?
    • 我正在寻找的解决方案是在上面的控制器中公开诸如Latest(..)之类的动作。由于有不止一个 GET,我将不得不告诉路由,当我调用控制器/动作时,然后调用动作。 ApiWitAction 是实现这一目标的途径。如果我没有任何路由并直接调用最新消息,它仍然会说“找到与请求匹配的多个操作:”我可以理解为什么会发生这种情况,但我不知道如何解决。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-28
    • 1970-01-01
    • 2014-09-12
    • 1970-01-01
    • 1970-01-01
    • 2015-11-02
    • 1970-01-01
    相关资源
    最近更新 更多