How to send a list of integers to web api 2 get request?

本小妞迷上赌 提交于 2019-12-04 06:27:04

You'll need custom model binder to get this working. Here's simplified version you can start work with:

public class CsvIntModelBinder : IModelBinder
{
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        var key = bindingContext.ModelName;
        var valueProviderResult = bindingContext.ValueProvider.GetValue(key);
        if (valueProviderResult == null)
        {
            return false;
        }

        var attemptedValue = valueProviderResult.AttemptedValue;
        if (attemptedValue != null)
        {
            var list = attemptedValue.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).
                       Select(v => int.Parse(v.Trim())).ToList();

            bindingContext.Model = list;
        }
        else
        {
            bindingContext.Model = new List<int>();
        }
        return true;
    }
}

And use it this way (remove {ids} from route):

[HttpGet]
[Route("api/NewHotelData")]
public HttpResponseMessage Get([ModelBinder(typeof(CsvIntModelBinder))] List<int> ids)

If you want to keep {ids} in route, you should change client request to:

api/NewHotelData/1,2,3,4

Another option (without custom model binder) is changing get request to:

?ids=1&ids=2&ids=3

Using custom model binder as suggested in comments is the proper way to do this. However, you can also do it the quick-and-dirty way like so:

[HttpGet]
[Route("api/NewHotelData")]
public HttpResponseMessage Get([FromUri] string ids)
{
    var separated = ids.Split(new char[] { ',' });
    List<int> parsed = separated.Select(s => int.Parse(s)).ToList();
}

First, I'm splitting the uri ids string and then I'm converting them into a list of integers using Linq. Please beware that this is missing sanity checks and will throw expections if the arguments are in incorrect format.

You call it like this: http://192.168.9.43/api/NewHotelData?ids=5,10,20

Update: Personally, I think that using the model binder for a simple thing like this is over-engineering. You need a lot of code to make thing this simple work. The code you would use in a model binder is actually very similar, you would just get a nicer syntax of the method argument. If you wrap the integer parsing into a try-catch block and return an appropriate error message in case of bad format, I don't see a reason why not to use this approach.

Apparently this could work out of the box:

http://192.168.9.43/api/NewHotelData/?ids=1&ids=2&ids=3&ids=4

That is, repeating the parameter name with the different values. But what would happen if those ids became huge and you had to include a lot of them, potentially making the URL too long?

I think it would be cleaner to just make it a POST request and be done with it, though. You wrote that you need the request to be a GET and not a POST, but why? Using POST to retrieve things is perfectly acceptable in the context of AJAX requests.

This might be too tacky, but one could also do something like:
In your .NET class (model):

public class TackyList
{
     public IEnumerable<int> myIntList {get; set;}
}

On the client side you'd do a post i.e: {myIntList: [4,2,0]}

Now the action/method on your controller would look something like:

public void myApiMethodThatDoesSomethingWith(TackyList tl)
{
   // here you should be able to do something like:
   if(tl != null && tl.Count > 0) // blah
}
[HttpGet]
[Route("api/getsomething")]
public HttpResponseMessage Get([FromUri] params int[] ids)
{
}

Usage: http GET localhost:9000/api/getsomething?ids=1&ids=5&ids=9

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