52

I want to do this, but I want to also be able to pass in arrays into the query string. I've tried things like:

http://www.sitename.com/route?arr[]=this&arr[]=that
http://www.sitename.com/route?arr[]=this&that
http://www.sitename.com/route?arr[0]=this&arr[1]=that
http://www.sitename.com/route?arr0=this&arr1=that
http://www.sitename.com/route?arr=this&arr=that

And my route in the C# code looks like this:

[Route("route")]
[HttpGet]
public void DoSomething(string[] values)
{
    // ...
}

But in all of these cases, values is always null when it gets to the C# code. What do I need my query string to be to pass an array of strings?

Ilya Chumakov
  • 23,161
  • 9
  • 86
  • 114
user3685285
  • 6,066
  • 13
  • 54
  • 95

8 Answers8

53

Use a parameter name in the query string. If you have an action:

public void DoSomething(string[] values)

Then use values in the query string to pass an array to a server:

?values=this&values=that
Ilya Chumakov
  • 23,161
  • 9
  • 86
  • 114
  • 6
    That's in the list of things I tried. It didn't work for me. – user3685285 Apr 13 '17 at 20:55
  • @user3685285, I checked it and it works as described. Could you pass a single value to the action like `Foo(string value)` ? – Ilya Chumakov Apr 13 '17 at 21:02
  • This is how I knew how to do it, but it did not work for me either. `Unexpected end of Stream, the content may have already been read by another component` – Sinaesthetic Apr 11 '18 at 16:41
  • @Sinaesthetic how can a stream reading be related to a model binding? – Ilya Chumakov Apr 11 '18 at 18:20
  • I mean... everything is a stream coming over the wire, so it's probably happening during binding. I don't know; that's just the message that's coming out. If I use a single value with `string` instead of `string[]` it is fine – Sinaesthetic Apr 13 '18 at 01:45
  • 1
    Are you missing the [FromUri] attribute? – keuleJ Aug 02 '18 at 12:16
  • @IlyaChumakov Did you test this on .NET Core ? I mean I have it working on .NET 4.6.2 WebApi but can't seem to get it working in Core 2.1 Version – cah1r Aug 09 '18 at 16:14
  • 4
    @MateuszMigała yes, it worked on 1.1 but there is a bug on Core 2.1 as described in the answer https://stackoverflow.com/a/52222184/5112433. The bug was fixed in 2.2. – Ilya Chumakov Mar 20 '19 at 11:19
43

Delimited string is not the standard. Think also about the client if you support swagger or other generators.

For those who wonder about .net core 2.1 bug which receives an empty list, the work around is here: https://github.com/aspnet/Mvc/issues/7712#issuecomment-397003420

It needs a name parameter on FromQuery

[FromQuery(Name = "employeeNumbers")] List<string> employeeNumbers
Adel Tabareh
  • 1,478
  • 14
  • 10
  • Is this a bad practise to use a named parameter to use complex types with `[FromQuery]` attribute? – student18 Nov 12 '18 at 10:52
  • 1
    Array and list behave similarly in this context. But even though this answer is out of the context of current question, I would say, no it's not a bad practice. you can even have complex types like Person and feed it's properties via FromQuery: Look at this for more info: https://learn.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api – Adel Tabareh Nov 12 '18 at 13:15
  • 1
    I don't have any idea why, but this worked like a charm, thank you so much! Before naming my parameter like your answers says I was getting a 415 HTTP error, now everything is 200. – Machado Jan 16 '19 at 16:59
  • This answer is solving the wrong problem/ is out of date. You don't need the name param if you match the param name to the values passed in, as other answers point out. – Cory-G Jan 29 '19 at 20:52
  • 2
    My querystring was in `?arr[]=this&arr[]=that` format, and the only way I could get it to work was by including the square brackets in the FromQuery name: `[FromQuery(Name = "employeeNumbers[]")] List employeeNumbers`. I've no idea whether that is valid or not. – GuyB Jul 26 '19 at 19:46
35

I have found a solution. For example, if you have a query like this:

http://www.sitename.com/route?arr[]=this&arr[]=that

You must define in parameter as [FromQuery(Name = "arr[]")]. The name of parameter must include square brackets. As result we can see:

public void DoSomething([FromQuery(Name = "arr[]")] string[] arr)
John
  • 1,268
  • 16
  • 25
Alex
  • 601
  • 7
  • 11
8

I had to do something similar to this, but instead of strings, i used a list of long to pass some id for a search. Using a multiple select option, the chosen values are sent to the method (via get) like this:

[HttpGet("[action]")]
public IActionResult Search(List<long> idsSelected)
{
    ///do stuff here
}

I also use Route("[controller]") before the class declaration. Works just fine, but the list of items is broken into multiple parameters in the url, as shown below.

http://localhost:5000/Search/idsSelected=1&idsSelected=2
Pablo
  • 361
  • 3
  • 6
7

In the end, I just passed in a single delimited string, then used string.Split to separate on the server side. Not the prettiest solution, but it works. Until someone comes up with a better answer, this is all I got. I should reiterate that I'm using .NET Core, and these query strings are framework specific.

Update: An (arguable) benefit of this approach is that you pass the values together (e.g. arr=value1,value2) instead of repeating the key (arr=value1&arr=value2).

Michael Freidgeim
  • 26,542
  • 16
  • 152
  • 170
user3685285
  • 6,066
  • 13
  • 54
  • 95
  • In your example, you had arr=1&arr=2 but your variable name is values, so it should surely be values=1&values=2 The name must match. – Simon Aug 27 '18 at 15:02
  • Think about the tools that generate client for your api. I would prefer to see an array of ids as parameter to the client instead of an string parameter which is not self describing. – Adel Tabareh Nov 12 '18 at 13:20
  • @MohsenTabareh That's what I was asking. But no one could come up with a way that worked for me. So I just had to do the cheap hack. See the comments in Ilya's answer. Read the context before downvoting please... – user3685285 Nov 12 '18 at 15:30
  • And have you tried the solutions that I & @abatishchev provided? – Adel Tabareh Nov 12 '18 at 15:56
  • Well I'm not even working at that company anymore. I asked this question more than a year ago. Not sure if there was any updates to .NET Core that addressed this. – user3685285 Nov 12 '18 at 16:19
  • @user3685285 This is not an answer but workaround – Roi Shabtai Jun 30 '22 at 11:33
6

I found two problems in your question:

  1. Your query has parameters named arr while you Contrller's Action has values.
  2. I don't know why, but you gotta name your parameter (as answered here) so the Asp .NET ModelBinder can work as expected. Like this:
public void DoSomething([FromQuery(Name = "values")] string[] values)

After doing that, everything should work as expected.

Machado
  • 8,965
  • 6
  • 43
  • 46
5

Given:

public ValuesController
{
    public IACtionResult Get([FromUri]string[] arr)
    {
        Return Ok(arr.Length);
    }
}

The following request will work:

GET /api/values/?arr[0]=a&arr[1]=b&arr[2]=c
thepirat000
  • 12,362
  • 4
  • 46
  • 72
abatishchev
  • 98,240
  • 88
  • 296
  • 433
4

I had the same problem with .NET Core 3, while trying to pass in a string Array. I solved it by passing in the query parameter as a temporary json string. I then deserialized the string to the resulting array using Newtonsoft's Json package

using Newtonsoft.Json;

public IActionResult Get([FromQuery(Name = "array")] string arrayJson)
{
    List<string> array = JsonConvert.DeserializeObject<List<string>>(arrayJson);
}
  • 1
    The solution is very similar to the accepted answer https://stackoverflow.com/a/43474678/52277 and user3685285’s Split is more simple than JsonConvert.DeserializeObject> – Michael Freidgeim Oct 25 '20 at 20:09
  • It's annoying to have to do this but in the end, I couldn't find an easier solution when using deep objects. – Justin Harris Jun 07 '21 at 22:06
  • [FromQuery(Name = "array")] attribute is a better approach than split as it is strongly typed. When using split, you have to write code to type check and then convert. – Moiz Tankiwala Feb 21 '23 at 07:02