Webapi Routing with Integer array and Actions

為{幸葍}努か 提交于 2019-12-13 04:56:31

问题


This issue is driving me nuts.

I have a get method that takes ID array with custom ModelBinder (I can call http://xckvjl.com/api/results/1,23,34,)

I want to introduce Gets on actions. (so that I can call as http://alskjdfasl.com/api/results/latest)

I have the following web api routing.

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

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

I have tried with (Please note here that I am using my custom model binder)

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

You can reproduce this error with this sample:

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

If I write as:

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

It works. However, I want global level routing. Otherwise for every action I will have to write the same.

Please advise.


回答1:


So here's the dilimma:

With this route definition:

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

when you call http://alskjdfasl.com/api/results/latest, latest becomes the value of id, which obviously will throw error since string cannot be converted to int array.

Adding this route definition

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

won't help since now you either have to deal with order or define routes for your other actions which are now being masked due to this.

Without declaring routes at individual level, the only other options are to make the templates different or create your own route constraint that understands arrays.

I would give these a shot first:

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");

If nothing works, I would say go with attribute routes. They are cleaner.



来源:https://stackoverflow.com/questions/26052378/webapi-routing-with-integer-array-and-actions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!