80

I'm looking for the simplest way of converting a query string from an HTTP GET request into a Dictionary, and back again.

I figure it's easier to carry out various manipulations on the query once it is in dictionary form, but I seem to have a lot of code just to do the conversion. Any recommended ways?

14 Answers14

73

HttpUtility.ParseQueryString() parses query string into a NameValueCollection object, converting the latter to an IDictionary<string, string> is a matter of a simple foreach. This, however, might be unnecessary since NameValueCollection has an indexer, so it behaves pretty much like a dictionary.

Anton Gogolev
  • 113,561
  • 39
  • 200
  • 288
  • and back again: http://stackoverflow.com/questions/829080/how-to-build-a-query-string-for-a-url-in-c – Rudi Aug 16 '12 at 12:06
  • 16
    Request.QueryString is Already a NameValueCollection, @H70 answer is the easiest for putting into a dictionary `var parameters = Request.QueryString.Keys.Cast().ToDictionary(k => k, v => Request.QueryString[v]);` – johnny 5 Jan 29 '15 at 19:27
  • I've just tried to use it, and I think it has a problem: the resultant `NameValueCollection` values are silently modified when iterated. For example, try calling `var q = HttpUtility.ParseQueryString("firstParam=cGFzc35+d29yZA==")` (this is the base64 encoding for the string `pass~~word`), and then iterate it using `for (var i = 0; i <= q.Keys.Count; ++i) { var val = q[q.Keys[i]]; }`. Watch `val`'s value: You'll get `cGFzc35 d29yZA==` instead of `cGFzc35+d29yZA==`. – OfirD Oct 30 '19 at 11:51
  • @OfirD - There's an overload which takes in encoding - https://learn.microsoft.com/en-us/dotnet/api/system.web.httputility.parsequerystring?view=net-7.0#system-web-httputility-parsequerystring(system-string-system-text-encoding) – Ashish Agrawal Jul 25 '23 at 07:42
45

Here is how I usually do it

Dictionary<string, string> parameters = HttpContext.Current.Request.QueryString.Keys.Cast<string>()
    .ToDictionary(k => k, v => HttpContext.Current.Request.QueryString[v]);
Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
H7O
  • 859
  • 8
  • 5
22

How about HttpUtility.ParseQueryString?

Just add a reference to System.Web.dll

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
20

Same as Sean, but with Linq (and a function you can copy and paste):

public static Dictionary<string, string> ParseQueryString(string queryString)
{
   var nvc = HttpUtility.ParseQueryString(queryString);
   return nvc.AllKeys.ToDictionary(k => k, k => nvc[k]);
}

Also, the question asked how to get it back into a query string:

public static string CreateQueryString(Dictionary<string, string> parameters)
{
   return string.Join("&", parameters.Select(kvp => 
      string.Format("{0}={1}", kvp.Key, HttpUtility.UrlEncode(kvp.Value))));
}
ThisGuy
  • 2,335
  • 1
  • 28
  • 34
12

Just had to do this for a mono compatible solution

Regex.Matches(queryString, "([^?=&]+)(=([^&]*))?").Cast<Match>().ToDictionary(x => x.Groups[1].Value, x => x.Groups[3].Value)
Jon Canning
  • 1,602
  • 16
  • 16
  • Works for Windows Phone 8 too (the `HttpUtility.ParseQueryString` doesn't exist there too). – JWL Aug 12 '13 at 14:14
  • @BinaryWorrier and if they're not a simple .GroupBy(x => x.Groups[1].Value).ToDictionary(g => g.Key, g => g.First().Groups[3].Value); would work (with obvious data loss) – Drakarah Mar 28 '15 at 19:19
  • This answer is perfect for me, since I'm programming C# within Unity. Kinda surprised a solution for that environment was so hard to find, but oh well. – jhocking Apr 02 '20 at 22:36
  • btw this code relies on 'System.Linq' and 'System.Text.RegularExpressions;' – jhocking Apr 02 '20 at 22:37
10

In ASP.NET Core, use ParseQuery.

var query = HttpContext.Request.QueryString.Value;
var queryDictionary = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(query);
James Lawruk
  • 30,112
  • 19
  • 130
  • 137
7

I like the brevity of Jon Canning's answer, but in the interest of variety, here is another alternative to his answer, that would also work for restricted environments like Windows Phone 8, that lack the HttpUtility.ParseQueryString() utility:

    public static Dictionary<string, string> ParseQueryString(String query)
    {
        Dictionary<String, String> queryDict = new Dictionary<string, string>();
        foreach (String token in query.TrimStart(new char[] { '?' }).Split(new char[] { '&' }, StringSplitOptions.RemoveEmptyEntries))
        {
            string[] parts = token.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries);
            if (parts.Length == 2)
                queryDict[parts[0].Trim()] = HttpUtility.UrlDecode(parts[1]).Trim();
            else
                queryDict[parts[0].Trim()] = "";
        }
        return queryDict;
    }

Actually, a useful improvement to Canning's answer that take care of decoding url-encoded values (like in the above solution) is:

    public static Dictionary<string, string> ParseQueryString2(String query)
    {
       return Regex.Matches(query, "([^?=&]+)(=([^&]*))?").Cast<Match>().ToDictionary(x => x.Groups[1].Value, x => HttpUtility.UrlDecode( x.Groups[3].Value ));
    }
Community
  • 1
  • 1
JWL
  • 13,591
  • 7
  • 57
  • 63
7

One liner without HttpUtility

var dictionary = query.Replace("?", "").Split('&').ToDictionary(x => x.Split('=')[0], x => x.Split('=')[1]);
vicentedealencar
  • 913
  • 1
  • 10
  • 20
  • ok, I haven't thought of that use case. You could add `.Where(x => !String.IsNullOrEmpty(x))` before the `.ToDictionary` to avoid that exception – vicentedealencar Mar 09 '15 at 19:38
  • You can simply add a StringSplitOptions.RemoveEmptyEntries parameter to .Split('&'): .Split(new [] { '&' }, StringSplitOptions.RemoveEmptyEntries) – Rezgar Cadro Sep 27 '17 at 20:35
6

Yet another way to do it:

NameValueCollection nvcData = HttpUtility.ParseQueryString(queryString);
Dictionary<string, string> dictData = new Dictionary<string, string>(nvcData.Count);
foreach (string key in nvcData.AllKeys)
{
    dictData.Add(key, nvcData.Get(key));
}
Sean Colombo
  • 1,459
  • 17
  • 24
1

Most simple:

Dictionary<string, string> parameters = new Dictionary<string, string>();

for (int i = 0; i < context.Request.QueryString.Count; i++)
{
    parameters.Add(context.Request.QueryString.GetKey(i), context.Request.QueryString[i]);
}
Bruno Leitão
  • 764
  • 10
  • 16
1

Instead of converting HttpContext.Request.QueryString to Dictionary<>, try using

HttpContext.Request.Query

which already is a Dictionary<string, StringValues>

blackboxlogic
  • 557
  • 6
  • 13
1

I stumbled across this post whilst looking for the same solution for an Azure WebJob, hopefully this helps others doing the same.

If you are coding an Azure WebJob you use the GetQueryParameterDictionary() extension method.

var queryParameterDictionary = request.GetQueryParameterDictionary();

where request is of type HttpRequest and queryParameterDictionary is now of type IDictionary<string, string>

David B
  • 889
  • 2
  • 11
  • 29
1

You can just get it by decorating the parameter with the FromQueryAttribute

public void Action([FromQuery] Dictionary<string, string> queries)
{
    ...
}

P.S. If you want to get multiple values for each key you can change the Dictionary to Dictionary<string, List<string>>

Mendy
  • 7,612
  • 5
  • 28
  • 42
0

AspNet Core now automatically includes HttpRequest.Query which can be used similar to a dictionary with key accessors.

However if you needed to cast it for logging or other purposes, you can pull out that logic into an extension method like this:

public static class HttpRequestExtensions
{
  public static Dictionary<string, string> ToDictionary(this IQueryCollection query)
  {
    return query.Keys.ToDictionary(k => k, v => (string)query[v]);
  }
}

Then, you can consume it on your httpRequest like this:

var params = httpRequest.Query.ToDictionary()

Further Reading

KyleMit
  • 30,350
  • 66
  • 462
  • 664