3

How to pass int[] to HttpGet method in ASP.NET Core? (Not as query parameters!)

Every post I found talks about query params, but query params are not required.

I would like something like that:

[HttpGet("List/{ids}")]
public async Task<ActionResult<ViewItemModel[]>> List(int[] ids)

but ids are empty array. I call controller method with url: http://localh.../List/2062,2063,2064.
Swagger (Swashbuckle) calls method exactly the same.

I found this post but it is 5 years old and not for ASP.NET Core.

4
  • 1
    Have a look at this and see if it helps. might need to make some minor adjustments as it was for previous version but it works stackoverflow.com/a/37768858/5233410 Commented Jul 25, 2018 at 10:35
  • In the end you will need a custom model binder. Commented Jul 25, 2018 at 10:37
  • Not sure anymore if this is duplicate. Accepted answer in link you provided is perfect and something I am looking for. Problem is it doesn't work in ASP.NET Core. Until that I will use your answer. Commented Jul 25, 2018 at 10:44
  • 1
    Ok no problem. If you get stuck ping me and I'll see where I can help. Commented Jul 25, 2018 at 10:45

1 Answer 1

3

All the credit goes more or less to Nkosi answer here.

public class EnumerableBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (!typeof(IEnumerable<int>).IsAssignableFrom(bindingContext.ModelType))
            throw new OpPISException("Model is not assignable from IEnumerable<int>.");

        var val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        if (val == null)
            throw new NullReferenceException();

        var ids = val.Values.FirstOrDefault();
        if (ids == null)
            throw new NullReferenceException();

        var tokens = ids.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
        if (tokens.Length > 0)
        {
            try 
            {
                var clientsId = tokens.Select(int.Parse);
                object model = null;
                if (bindingContext.ModelType.IsArray)
                {
                    model = clientsId.ToArray();
                }
                else if (bindingContext.ModelType == typeof(HashSet<int>))
                {
                    model = clientsId.ToHashSet();
                }
                else
                {
                    model = clientsId.ToList();
                }                        
                bindingContext.ModelState.SetModelValue(bindingContext.ModelName, model);
                bindingContext.Result = ModelBindingResult.Success(model);
                return Task.CompletedTask;
            }
            catch {
                //...
            }
        }

        //If we reach this far something went wrong
        bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, "Cannot convert.");
        bindingContext.Result = ModelBindingResult.Failed();
        return Task.CompletedTask;
    }
}

Use case:

[HttpGet("List/{ids}")]
public async Task<ActionResult<ViewItemModel[]>> List([ModelBinder(typeof(EnumerableBinder))]HashSet<int> ids)
{
    //code
}

With a little reflection this could be changed to use also other types then int.

Sign up to request clarification or add additional context in comments.

1 Comment

Did some minor refactoring.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.