86

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 Answers 14

77

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.

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

4 Comments

Request.QueryString is Already a NameValueCollection, @H70 answer is the easiest for putting into a dictionary var parameters = Request.QueryString.Keys.Cast<string>().ToDictionary(k => k, v => Request.QueryString[v]);
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 - There's an overload which takes in encoding - learn.microsoft.com/en-us/dotnet/api/…
46

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]);

3 Comments

Easy and straightforward! Deserves a +1 :-)
for elegant answer
Note that they key can be null, which will cause the statement to fail. I fixed it by changing ".ToDictionary(k => k,..." to ".ToDictionary(k => k ?? "", ...". (You can use any default value for "k" that you want.)
22

How about HttpUtility.ParseQueryString?

Just add a reference to System.Web.dll

Comments

21

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))));
}

Comments

14

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)

5 Comments

Works for Windows Phone 8 too (the HttpUtility.ParseQueryString doesn't exist there too).
@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)
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.
btw this code relies on 'System.Linq' and 'System.Text.RegularExpressions;'
[HttpGet] public IHttpActionResult GetOrder([FromUri]object args) { var argsDictionary = Regex.Matches(RequestContext.Url.Request.RequestUri.Query, "([^?=&]+)(=([^&]*))?") .Cast<Match>() .ToDictionary(x => x.Groups[1].Value, x => x.Groups[3].Value);
10

In ASP.NET Core, use ParseQuery.

var query = HttpContext.Request.QueryString.Value;
var queryDictionary = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(query);

Comments

8

One liner without HttpUtility

var dictionary = query.Replace("?", "").Split('&').ToDictionary(x => x.Split('=')[0], x => x.Split('=')[1]);

2 Comments

ok, I haven't thought of that use case. You could add .Where(x => !String.IsNullOrEmpty(x)) before the .ToDictionary to avoid that exception
You can simply add a StringSplitOptions.RemoveEmptyEntries parameter to .Split('&'): .Split(new [] { '&' }, StringSplitOptions.RemoveEmptyEntries)
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 ));
    }

Comments

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));
}

Comments

2

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>>

Comments

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]);
}

1 Comment

Add a description to your code segment, Just the code block wont help much.
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>

Comments

1

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

HttpContext.Request.Query

which already is a Dictionary<string, StringValues>

Comments

1

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

var x = Current.Request.Query["x"];

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 queryParams = Current.Request.Query.ToDictionary()

Further Reading

Comments

Your Answer

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