264

If I wish to submit a http get request using System.Net.HttpClient there seems to be no api to add parameters, is this correct?

Is there any simple api available to build the query string that doesn't involve building a name value collection and url encoding those and then finally concatenating them? I was hoping to use something like RestSharp's api (i.e AddParameter(..))

Mike Perrenoud
  • 66,820
  • 29
  • 157
  • 232
NeoDarque
  • 3,222
  • 3
  • 19
  • 21
  • 1
    @Michael Perrenoud you may want to reconsider using the accepted answer with characters which need encoding, see my explanation below – illegal-immigrant Jul 06 '15 at 13:59

17 Answers17

418

If I wish to submit a http get request using System.Net.HttpClient there seems to be no api to add parameters, is this correct?

Yes.

Is there any simple api available to build the query string that doesn't involve building a name value collection and url encoding those and then finally concatenating them?

Sure:

var query = HttpUtility.ParseQueryString(string.Empty);
query["foo"] = "bar<>&-baz";
query["bar"] = "bazinga";
string queryString = query.ToString();

will give you the expected result:

foo=bar%3c%3e%26-baz&bar=bazinga

You might also find the UriBuilder class useful:

var builder = new UriBuilder("http://example.com");
builder.Port = -1;
var query = HttpUtility.ParseQueryString(builder.Query);
query["foo"] = "bar<>&-baz";
query["bar"] = "bazinga";
builder.Query = query.ToString();
string url = builder.ToString();

will give you the expected result:

http://example.com/?foo=bar%3c%3e%26-baz&bar=bazinga

that you could more than safely feed to your HttpClient.GetAsync method.

Eli_B
  • 163
  • 2
  • 10
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • I've used the `ParseQueryString` method as well, works good man. – Matthew Jun 13 '13 at 20:29
  • 12
    That's the absolute best in terms of url handling in .NET. No need to ever be manually url encoding and doing string concatenations or string builders or whatever. The UriBuilder class will even handle urls with fragments (`#`) for you using the Fragment property. I have seen so many people doing the mistake of manually handling urls instead of using the built-in tools. – Darin Dimitrov Jun 13 '13 at 20:30
  • 4
    I agree that it's definitely the easiest to use, but it's dealing with undocumented functionality. If you were to do `new NameValueCollection` (which `ParseQueryString` returns), you cannot do `.ToString()` on it and expect the same results. – Matthew Jun 13 '13 at 20:34
  • 2
    What do you mean by undocumented functionality? The ParseQueryString method returns a derived class of NameValueCollection which takes care of all the url encoding for you. The [`ParseQueryString`](http://msdn.microsoft.com/en-us/library/ms150046.aspx) seems pretty well documented. – Darin Dimitrov Jun 13 '13 at 20:35
  • 8
    `NameValueCollection.ToString()` normally does not make query strings, and there's no documentation stating that doing a `ToString` on the result of `ParseQueryString` will result in a new query string, thus could break at any time as there's no guarantee in that functionality. – Matthew Jun 13 '13 at 20:38
  • 12
    HttpUtility is in System.Web which is not available on portable runtime. It seems strange that this functionality isn't more generally available in the class libraries. – Chris Eldredge Jul 29 '13 at 22:21
  • 107
    This solution is despicable. .Net should have proper querystring builder. – Kugel Sep 18 '13 at 03:21
  • 1
    @Kugel How is .NET's proper querystring builder or lack thereof related to this answer's despicability or lack thereof? – Zev Spitz Oct 30 '14 at 12:09
  • 13
    The fact that the best solution is hidden in the internal class to which you can only get by calling an utility method passing in empty string can't be exactly called an elegant solution. – Kugel Oct 30 '14 at 12:13
  • 3
    This solution works well but I don't like having to include System.Web to use it. – Rostov Nov 04 '14 at 20:35
  • 5
    I assume this would not work for producing a query string with multiple values for a key (eg. `foo=1&foo=2&foo=3`)? Any convenient alternatives? – label17 Nov 24 '14 at 01:11
  • @DarinDimitrov just wanted to give you guys the heads up - DO NOT use builder.Uri (which I expected to be proper way to get Uri), as it will give double encoded url, see my answer – illegal-immigrant Jul 06 '15 at 13:37
  • 2
    @label17 It does work if you use the syntax: `query.Add("foo", "1");`, since `ParseQueryString` parses into a NameValueCollection which allowes duplicates. – Philip Dec 01 '15 at 13:35
  • For those thinking about the `System.Web` namespace, the `HttpUtility` is available in .Net Standard and .Net Core unlike most other classes in the namespace which means they're not getting deprecated any time soon and will continue being a standard way of doing this. – bokibeg Sep 16 '19 at 11:51
  • Can you explain in the answer why you set port to -1? – christiaantober Jan 03 '23 at 13:25
105

For those who do not want to include System.Web in projects that don't already use it, you can use FormUrlEncodedContent from System.Net.Http and do something like the following:

keyvaluepair version

string query;
using(var content = new FormUrlEncodedContent(new KeyValuePair<string, string>[]{
    new KeyValuePair<string, string>("ham", "Glazed?"),
    new KeyValuePair<string, string>("x-men", "Wolverine + Logan"),
    new KeyValuePair<string, string>("Time", DateTime.UtcNow.ToString()),
})) {
    query = content.ReadAsStringAsync().Result;
}

dictionary version

string query;
using(var content = new FormUrlEncodedContent(new Dictionary<string, string>()
{
    { "ham", "Glaced?"},
    { "x-men", "Wolverine + Logan"},
    { "Time", DateTime.UtcNow.ToString() },
})) {
    query = content.ReadAsStringAsync().Result;
}
Cristian Ciupitu
  • 20,270
  • 7
  • 50
  • 76
Rostov
  • 2,516
  • 2
  • 23
  • 17
  • Why do you use a using statement? – Ian Warburton Nov 14 '17 at 21:00
  • Likely to free up resources, but this is over-the-top. Don't do this. – Kody Jan 05 '18 at 20:31
  • 7
    This can be more concise by using Dictionary instead of the KVP array. Then using initializer syntax of: { "ham", "Glazed?" } – Sean B Apr 12 '18 at 19:34
  • @SeanB That's a nice idea, especially when using something to add a dynamic / unknown list of parameters. For this example since it's a "fixed" list, I didn't feel like the overhead of a dictionary was worth it. – Rostov Apr 13 '18 at 14:32
  • 9
    @Kody Why do you say to not to use `dispose`? I always dispose unless I have a good reason not to, like reusing `HttpClient`. – Dan Friedman Jul 16 '18 at 22:51
  • @DanFriedman I think he meant that the _solution_ is over the top, as it requires allocating several new objects and running an asynchronous operation. – Kevin May 01 '21 at 01:03
93

In a ASP.NET Core project you can use the QueryHelpers class, available in the Microsoft.AspNetCore.WebUtilities namespace for ASP.NET Core, or the .NET Standard 2.0 NuGet package for other consumers:

// using Microsoft.AspNetCore.WebUtilities;
var query = new Dictionary<string, string>
{
    ["foo"] = "bar",
    ["foo2"] = "bar2",
    // ...
};

var response = await client.GetAsync(QueryHelpers.AddQueryString("/api/", query));
Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
Markus
  • 3,871
  • 3
  • 23
  • 26
  • 5
    Its annoying that although with this process you still cannot send multiple value for the same key. If you want to send "bar" and "bar2" as part of just foo, it is not possible. – m0g Apr 20 '18 at 19:03
  • 3
    This is a great answer for modern apps, works in my scenario, simple and clean. However, I don't need any escape mechanisms - not tested. – Patrick Stalph Dec 18 '18 at 09:18
  • 1
    This NuGet package targets .NET standard 2.0 which means you can use it on the full .NET framework 4.6.1+ – eddiewould Jul 25 '19 at 01:50
  • Also available in `Microsoft.Owin.Infrastructure.WebUtilities.AddQueryString()` according to https://stackoverflow.com/a/40308437/470014 – Caltor Feb 16 '23 at 17:25
  • I found this solution useful. I just extended this solution like below and used it. public static async Task GetAsync(this HttpClient httpClient, string url, Dictionary queries) { string uri = QueryHelpers.AddQueryString(url, queries); return await httpClient.GetAsync(uri).ConfigureAwait(false); } – Lakshmanan Dhamotharan May 30 '23 at 14:33
51

TL;DR: do not use accepted version as It's completely broken in relation to handling unicode characters, and never use internal API

I've actually found weird double encoding issue with the accepted solution:

So, If you're dealing with characters which need to be encoded, accepted solution leads to double encoding:

  • query parameters are auto encoded by using NameValueCollection indexer (and this uses UrlEncodeUnicode, not regular expected UrlEncode(!))
  • Then, when you call uriBuilder.Uri it creates new Uri using constructor which does encoding one more time (normal url encoding)
  • That cannot be avoided by doing uriBuilder.ToString() (even though this returns correct Uri which IMO is at least inconsistency, maybe a bug, but that's another question) and then using HttpClient method accepting string - client still creates Uri out of your passed string like this: new Uri(uri, UriKind.RelativeOrAbsolute)

Small, but full repro:

var builder = new UriBuilder
{
    Scheme = Uri.UriSchemeHttps,
    Port = -1,
    Host = "127.0.0.1",
    Path = "app"
};

NameValueCollection query = HttpUtility.ParseQueryString(builder.Query);

query["cyrillic"] = "кирилиця";

builder.Query = query.ToString();
Console.WriteLine(builder.Query); //query with cyrillic stuff UrlEncodedUnicode, and that's not what you want

var uri = builder.Uri; // creates new Uri using constructor which does encode and messes cyrillic parameter even more
Console.WriteLine(uri);

// this is still wrong:
var stringUri = builder.ToString(); // returns more 'correct' (still `UrlEncodedUnicode`, but at least once, not twice)
new HttpClient().GetStringAsync(stringUri); // this creates Uri object out of 'stringUri' so we still end up sending double encoded cyrillic text to server. Ouch!

Output:

?cyrillic=%u043a%u0438%u0440%u0438%u043b%u0438%u0446%u044f

https://127.0.0.1/app?cyrillic=%25u043a%25u0438%25u0440%25u0438%25u043b%25u0438%25u0446%25u044f

As you may see, no matter if you do uribuilder.ToString() + httpClient.GetStringAsync(string) or uriBuilder.Uri + httpClient.GetStringAsync(Uri) you end up sending double encoded parameter

Fixed example could be:

var uri = new Uri(builder.ToString(), dontEscape: true);
new HttpClient().GetStringAsync(uri);

But this uses obsolete Uri constructor

P.S on my latest .NET on Windows Server, Uri constructor with bool doc comment says "obsolete, dontEscape is always false", but actually works as expected (skips escaping)

So It looks like another bug...

And even this is plain wrong - it send UrlEncodedUnicode to server, not just UrlEncoded what server expects

Update: one more thing is, NameValueCollection actually does UrlEncodeUnicode, which is not supposed to be used anymore and is incompatible with regular url.encode/decode (see NameValueCollection to URL Query?).

So the bottom line is: never use this hack with NameValueCollection query = HttpUtility.ParseQueryString(builder.Query); as it will mess your unicode query parameters. Just build query manually and assign it to UriBuilder.Query which will do necessary encoding and then get Uri using UriBuilder.Uri.

Prime example of hurting yourself by using code which is not supposed to be used like this

Community
  • 1
  • 1
illegal-immigrant
  • 8,089
  • 9
  • 51
  • 84
  • 22
    Could you add a complete utility function to this answer which works? – mafu Mar 11 '16 at 20:04
  • 14
    I second mafu on this: I read through the answer but don't have a conclusion. Is there a definitive answer to this? – Richard Griffiths Mar 29 '16 at 14:12
  • 6
    I'd also like to see the definitive answer for this problem – Pones Mar 31 '16 at 12:54
  • The definitive answer to this problem is to use `var namedValues = HttpUtility.ParseQueryString(builder.Query)`, but then instead of using the returned NameValueCollection, immediately convert it to a Dictionary like so: `var dic = values.ToDictionary(x => x, x => values[x]);` Add new values to the dictionary, then pass it to the constructor of `FormUrlEncodedContent` and call `ReadAsStringAsync().Result` on it. That gives you a properly encoded query string, which you can assign back to the UriBuilder. – Triynko Dec 30 '16 at 15:59
  • You actually *can* just use NamedValueCollection.ToString instead of all that, but only if you change an app.config/web.config setting that prevents ASP.NET from using the '%uXXXX' encoding: ``. I wouldn't depend on this behavior, so it's better to use the FormUrlEncodedContent class, as demonstrated by an earlier answer: http://stackoverflow.com/a/26744471/88409 – Triynko Dec 30 '16 at 16:04
  • 1
    For people, who asked about alternative without double encoding issue - just use uriBuilder.Uri.ParseQueryString() instead of HttpUtility.ParseQueryString() – Valeriy Lyuchyn Apr 19 '17 at 15:36
36

You might want to check out Flurl [disclosure: I'm the author], a fluent URL builder with optional companion lib that extends it into a full-blown REST client.

var result = await "https://api.com"
    // basic URL building:
    .AppendPathSegment("endpoint")
    .SetQueryParams(new {
        api_key = ConfigurationManager.AppSettings["SomeApiKey"],
        max_results = 20,
        q = "Don't worry, I'll get encoded!"
    })
    .SetQueryParams(myDictionary)
    .SetQueryParam("q", "overwrite q!")

    // extensions provided by Flurl.Http:
    .WithOAuthBearerToken("token")
    .GetJsonAsync<TResult>();

Check out the docs for more details. The full package is available on NuGet:

PM> Install-Package Flurl.Http

or just the stand-alone URL builder:

PM> Install-Package Flurl

Todd Menier
  • 37,557
  • 17
  • 150
  • 173
  • 3
    Why not extend `Uri` or start with your own class instead of `string`? – mpen Sep 04 '14 at 16:57
  • 2
    Technically I did start with my own `Url` class. The above is equivalent to `new Url("https://api.com").AppendPathSegment...` Personally I prefer the string extensions due to fewer keystrokes and standardized on them in the docs, but you can do it either way. – Todd Menier Sep 04 '14 at 20:58
  • Off topic, but really nice lib, I'm using it after seeing this. Thanks for using IHttpClientFactory as well. – Ed S. Feb 11 '20 at 17:48
7

Along the same lines as Rostov's post, if you do not want to include a reference to System.Web in your project, you can use FormDataCollection from System.Net.Http.Formatting and do something like the following:

Using System.Net.Http.Formatting.FormDataCollection

var parameters = new Dictionary<string, string>()
{
    { "ham", "Glaced?" },
    { "x-men", "Wolverine + Logan" },
    { "Time", DateTime.UtcNow.ToString() },
}; 
var query = new FormDataCollection(parameters).ReadAsNameValueCollection().ToString();
cwills
  • 2,136
  • 23
  • 17
4

Since I have to reuse this few time, I came up with this class that simply help to abstract how the query string is composed.

public class UriBuilderExt
{
    private NameValueCollection collection;
    private UriBuilder builder;

    public UriBuilderExt(string uri)
    {
        builder = new UriBuilder(uri);
        collection = System.Web.HttpUtility.ParseQueryString(string.Empty);
    }

    public void AddParameter(string key, string value) {
        collection.Add(key, value);
    }

    public Uri Uri{
        get
        {
            builder.Query = collection.ToString();
            return builder.Uri;
        }
    }

}

The use will be simplify to something like this:

var builder = new UriBuilderExt("http://example.com/");
builder.AddParameter("foo", "bar<>&-baz");
builder.AddParameter("bar", "second");
var uri = builder.Uri;

that will return the uri: http://example.com/?foo=bar%3c%3e%26-baz&bar=second

Jaider
  • 14,268
  • 5
  • 75
  • 82
4

Good part of accepted answer, modified to use UriBuilder.Uri.ParseQueryString() instead of HttpUtility.ParseQueryString():

var builder = new UriBuilder("http://example.com");
var query = builder.Uri.ParseQueryString();
query["foo"] = "bar<>&-baz";
query["bar"] = "bazinga";
builder.Query = query.ToString();
string url = builder.ToString();
Jpsy
  • 20,077
  • 7
  • 118
  • 115
  • 2
    FYI: This requires a reference to [System.Net.Http](https://learn.microsoft.com/en-us/dotnet/api/system.net.http) as the `ParseQueryString()` extension method is not within `System`. – Sunny Patel Dec 24 '18 at 23:46
3

Darin offered an interesting and clever solution, and here is something that may be another option:

public class ParameterCollection
{
    private Dictionary<string, string> _parms = new Dictionary<string, string>();

    public void Add(string key, string val)
    {
        if (_parms.ContainsKey(key))
        {
            throw new InvalidOperationException(string.Format("The key {0} already exists.", key));
        }
        _parms.Add(key, val);
    }

    public override string ToString()
    {
        var server = HttpContext.Current.Server;
        var sb = new StringBuilder();
        foreach (var kvp in _parms)
        {
            if (sb.Length > 0) { sb.Append("&"); }
            sb.AppendFormat("{0}={1}",
                server.UrlEncode(kvp.Key),
                server.UrlEncode(kvp.Value));
        }
        return sb.ToString();
    }
}

and so when using it, you might do this:

var parms = new ParameterCollection();
parms.Add("key", "value");

var url = ...
url += "?" + parms;
Mike Perrenoud
  • 66,820
  • 29
  • 157
  • 232
  • 5
    You would want to encode `kvp.Key` and `kvp.Value` separately inside the for loop, not in the full query-string (thus not encoding the `&`, and `=` characters). – Matthew Jun 13 '13 at 20:27
  • Thanks Mike. The other proposed solutions (involving NameValueCollection) didn't work for me because I'm in a PCL project, so this was a perfect alternative. For others who are working on the client side, the `server.UrlEncode` can be replaced with `WebUtility.UrlEncode` – BCA Jun 01 '16 at 18:08
2

The RFC 6570 URI Template library I'm developing is capable of performing this operation. All encoding is handled for you in accordance with that RFC. At the time of this writing, a beta release is available and the only reason it's not considered a stable 1.0 release is the documentation doesn't fully meet my expectations (see issues #17, #18, #32, #43).

You could either build a query string alone:

UriTemplate template = new UriTemplate("{?params*}");
var parameters = new Dictionary<string, string>
  {
    { "param1", "value1" },
    { "param2", "value2" },
  };
Uri relativeUri = template.BindByName(parameters);

Or you could build a complete URI:

UriTemplate template = new UriTemplate("path/to/item{?params*}");
var parameters = new Dictionary<string, string>
  {
    { "param1", "value1" },
    { "param2", "value2" },
  };
Uri baseAddress = new Uri("http://www.example.com");
Uri relativeUri = template.BindByName(baseAddress, parameters);
Sam Harwell
  • 97,721
  • 20
  • 209
  • 280
1

Or simply using my Uri extension

Code

public static Uri AttachParameters(this Uri uri, NameValueCollection parameters)
{
    var stringBuilder = new StringBuilder();
    string str = "?";
    for (int index = 0; index < parameters.Count; ++index)
    {
        stringBuilder.Append(str + parameters.AllKeys[index] + "=" + parameters[index]);
        str = "&";
    }
    return new Uri(uri + stringBuilder.ToString());
}

Usage

Uri uri = new Uri("http://www.example.com/index.php").AttachParameters(new NameValueCollection
                                                                           {
                                                                               {"Bill", "Gates"},
                                                                               {"Steve", "Jobs"}
                                                                           });

Result

http://www.example.com/index.php?Bill=Gates&Steve=Jobs

Roman Ratskey
  • 5,101
  • 8
  • 44
  • 67
  • 31
    Didn't you forget URL encoding? – Kugel Sep 18 '13 at 03:23
  • 1
    this is a great example of using extensions to create clear, useful helpers. If you combine this with the accepted answer you're on your way to building a solid RestClient – emran Feb 20 '14 at 05:43
1

To avoid double encoding issue described in taras.roshko's answer and to keep possibility to easily work with query parameters, you can use uriBuilder.Uri.ParseQueryString() instead of HttpUtility.ParseQueryString().

Valeriy Lyuchyn
  • 223
  • 4
  • 10
1

My answer doesn't globally differ from the accepted/other answers. I just tried to create an extension method for the Uri type, which takes variable number of parameters.

public static class UriExtensions
{
    public static Uri AddParameter(this Uri url, params (string Name, string Value)[] @params)
    {
        if (!@params.Any())
        {
            return url;
        }

        UriBuilder uriBuilder = new(url);

        NameValueCollection query = HttpUtility.ParseQueryString(uriBuilder.Query);

        foreach (var param in @params)
        {
            query[param.Name] = param.Value.Trim();
        }

        uriBuilder.Query = query.ToString();

        return uriBuilder.Uri;
    }
}

Usage example:

var uri = new Uri("http://someuri.com")
    .AddParameter(
       ("p1.name", "p1.value"),
       ("p2.name", "p2.value"),
       ("p3.name", "p3.value"));
AEMLoviji
  • 3,217
  • 9
  • 37
  • 61
0

Thanks to "Darin Dimitrov", This is the extension methods.

 public static partial class Ext
{
    public static Uri GetUriWithparameters(this Uri uri,Dictionary<string,string> queryParams = null,int port = -1)
    {
        var builder = new UriBuilder(uri);
        builder.Port = port;
        if(null != queryParams && 0 < queryParams.Count)
        {
            var query = HttpUtility.ParseQueryString(builder.Query);
            foreach(var item in queryParams)
            {
                query[item.Key] = item.Value;
            }
            builder.Query = query.ToString();
        }
        return builder.Uri;
    }

    public static string GetUriWithparameters(string uri,Dictionary<string,string> queryParams = null,int port = -1)
    {
        var builder = new UriBuilder(uri);
        builder.Port = port;
        if(null != queryParams && 0 < queryParams.Count)
        {
            var query = HttpUtility.ParseQueryString(builder.Query);
            foreach(var item in queryParams)
            {
                query[item.Key] = item.Value;
            }
            builder.Query = query.ToString();
        }
        return builder.Uri.ToString();
    }
}
Waleed A.K.
  • 1,596
  • 13
  • 13
0
HttpClient client = new HttpClient();
var uri = Environment.GetEnvironmentVariable("URL of Api");
                
var requesturi = QueryHelpers.AddQueryString(uri, "parameter_name",parameter_value);
client.BaseAddress = new Uri(requesturi);

And then you can add request headers also eg:

client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("x-api-key", secretValue);

response syntax eg:

HttpResponseMessage response = client.GetAsync(requesturi).Result;

Hope it will work for you.

Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
Flame alchemist
  • 107
  • 1
  • 4
0

A better method is to use an extension method for HttpClient that takes a URL and an object containing the query string parameters, and automatically generates the complete URL with the parameters included

public static class HttpClientExtensions
{
    public static async Task<HttpResponseMessage> GetAsyncWithQueryString<T>(this HttpClient httpClient, string url, T queryObject)
    {
        UriBuilder uriBuilder = new UriBuilder(url);
        NameValueCollection query = HttpUtility.ParseQueryString(uriBuilder.Query);

        PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
        foreach (PropertyInfo property in properties)
        {
            string name = property.Name;
            string value = Convert.ToString(property.GetValue(queryObject, null));
            if (!string.IsNullOrWhiteSpace(value))
            {
                query[name] = HttpUtility.UrlEncode(value);
            }
        }

        uriBuilder.Query = query.ToString();

        // Remove unnecessary parts of the URL such as protocol and port
        string finalUrl = uriBuilder.ToString().Replace("http://", "").Replace(":80", "");

        return await httpClient.GetAsync(finalUrl);
    }
}

To use this extension method, simply call it on an instance of HttpClient, passing in the base URL and an object containing the query string parameters

MyQueryObject queryObject = new MyQueryObject { Param1 = "value1", Param2 = "value2" };

HttpResponseMessage response = await _httpClient.GetAsyncWithQueryString("https://example.com/api/carts", queryObject);
Ali Bayat
  • 3,561
  • 2
  • 42
  • 43
-3

I couldn't find a better solution than creating a extension method to convert a Dictionary to QueryStringFormat. The solution proposed by Waleed A.K. is good as well.

Follow my solution:

Create the extension method:

public static class DictionaryExt
{
    public static string ToQueryString<TKey, TValue>(this Dictionary<TKey, TValue> dictionary)
    {
        return ToQueryString<TKey, TValue>(dictionary, "?");
    }

    public static string ToQueryString<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, string startupDelimiter)
    {
        string result = string.Empty;
        foreach (var item in dictionary)
        {
            if (string.IsNullOrEmpty(result))
                result += startupDelimiter; // "?";
            else
                result += "&";

            result += string.Format("{0}={1}", item.Key, item.Value);
        }
        return result;
    }
}

And them:

var param = new Dictionary<string, string>
          {
            { "param1", "value1" },
            { "param2", "value2" },
          };
param.ToQueryString(); //By default will add (?) question mark at begining
//"?param1=value1&param2=value2"
param.ToQueryString("&"); //Will add (&)
//"&param1=value1&param2=value2"
param.ToQueryString(""); //Won't add anything
//"param1=value1&param2=value2"
Diego Mendes
  • 10,631
  • 2
  • 32
  • 36