Sivvie Lim
Sivvie Lim

Reputation: 1286

Any way to add arrays into HTTP request URI by using C#?

I want to send a HTTP request that looks like this: http://api.com/main?id=1234&id=5678, the id will be GUID in string eventually.

I tried the below piece of code:

var idString = string.Join(",", listOfIds);

var queryString = new Dictionary<string, string>
{
    {"id", idString}
};

requestUri = QueryHelpers.AddQueryString(requestUri, queryString);

This will give me like: http://api.com/main?id=1234,5678 but I want the style like above.

Is there anyway to achieve this without using for loop?

Upvotes: 1

Views: 2144

Answers (2)

David Liang
David Liang

Reputation: 21526

This will give me like: http://api.com/main?id=1234,5678 but I want the style like above, e.g., http://api.com/main?id=1234&id=5678

I think the accept answer didn't address this issue from OP.

Using AddQueryString(string uri, IEnumerable<KeyValuePair<string, string>> queryString) overload when you have an array you want to be part of the query string would only give you the comma-separated string as the parameter, and most of the time that is not what you want.

For example,

var endpoint = "v1/api/endpoint";
var arrayOfIds = new[] { "1", "2", "3" };
var queryString = new[]
{
    new KeyValuePair<string,string>("id",new StringValues(arrayOfIds)),
    new KeyValuePair<string,string>("other","value"),
    ...
};

var url = QueryHelpers.AddQueryString(endpoint, queryString);

The url at the end would look like (demo)

v1/api/endpoint?id=1,2,3&other=value

To get what OP wants, we will need to use the StringValues' overload AddQueryString(string uri, IEnumerable<KeyVaulePair<string, StringValues>> queryString).

For example,

var endpoint = "v1/api/endpoint";
var arrayOfIds = new[] { "1", "2", "3" };
var queryString = new []
{
    new KeyValuePair<string, StringValues>("id", new StringValues(arrayOfIds)),
    new KeyValuePair<string, StringValues>("other", "value")
};
        
var url = QueryHelpers.AddQueryString(endpoint, queryString);

Then the URL would look like (demo)

v1/api/endpoint?id=1&id=2&id=3&other=value

Bonus

Just in case you wonder why you don't see the StringValues' overload, even you are running on .NET 5+?

Maybe you have multiple versions of .NET installed, and your app is still referencing the old version 2.*, which is marked as deprecated recently.

To make sure you use the latest .NET, in your .csproj file, you can add the framework reference like the following:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
        ...
    </PropertyGroup>

    <ItemGroup>
        <FrameworkReference Include="Microsoft.AspNetCore.App" />
    </ItemGroup>

    ...
</Project>

Upvotes: 0

Panagiotis Kanavos
Panagiotis Kanavos

Reputation: 131706

QueryHelpers doesn't work with arrays because there's no standard way to pass an array of values in a query string. Some applications accept id=1,2,3 others id=1&id=2&id=3 while others id[0]=1&id[1]=2&id[2]=3.

.NET (Core) 5 and later

AddQueryString now works with lists of KeyValuePair<string,string>or KeyValuePair<string,StringValues>

var parameters=new []{
                   new KeyValuePair<string,string>("id",new StringValues(arrayOfIds)),
                   new KeyValuePair<string,string>("other","value"),
                   ...
               };
var finalUri=QueryHelpers.AddQueryString(requestUri, parameters);

The StringValues constructors accept either a single string or an array of strings

Before .NET (Core) 5

String.Join itself uses a loop and a StringBuilder to create a new string without allocating temporary strings. Strings are immutable, so any string modification operation results in a new temporary string.

You could use the source code as a guide to build your own loop. A quick solution could be something like this:

string ArrayToQueryString_DONT_USE(string name,string[] values)
{
    var result=new StringBuilder();
    result.AppendFormat("{0}={1}",name,value);
    for(int i=1;i<values.Length;i++)
    {
        result.AppendFormat("&{0}={1}',name,values[i]);
    }
    return result.ToString();
}

Unfortunately, that won't work if the parameter names or values need encoding. That's what AddQueryString does, using, once again, a StringBuilder to avoid allocating temporary strings. We can borrow that code as well:

string ArrayToQueryString(string name,string[] values)
{
    var result=new StringBuilder();
    result.AppendFormat("{0}={1}",name,value);
    for(int i=1;i<values.Length;i++)
    {
        result.Append('&');
        result.Append(UrlEncoder.Default.Encode(name));
        result.Append('=');
        result.Append(UrlEncoder.Default.Encode(values[i]));
    }
    return result.ToString();
}

Upvotes: 4

Related Questions