135

I have a uri string like: http://example.com/file?a=1&b=2&c=string%20param

Is there an existing function that would convert query parameter string into a dictionary same way as ASP.NET Context.Request does it.

I'm writing a console app and not a web-service so there is no Context.Request to parse the URL for me.

I know that it's pretty easy to crack the query string myself but I'd rather use a FCL function is if exists.

Ghostrider
  • 7,545
  • 7
  • 30
  • 44

9 Answers9

160

Use this:

string uri = ...;
string queryString = new System.Uri(uri).Query;
var queryDictionary = System.Web.HttpUtility.ParseQueryString(queryString);

This code by Tejs isn't the 'proper' way to get the query string from the URI:

string.Join(string.Empty, uri.Split('?').Skip(1));
Timothy Shields
  • 75,459
  • 18
  • 120
  • 173
  • 17
    Note that `Uri.Query` will only work on absolute Uri. On relative one it throws an `InvalidOperationExeception`. – ghord Jun 23 '13 at 11:46
  • 1
    Once you get `Query` from `Uri`, you can use `HttpUtility.ParseQueryString(uri.Query)` to get name value collection – Dhrumil Bhankhar May 06 '19 at 10:46
122

You can use:

var queryString = url.Substring(url.IndexOf('?')).Split('#')[0]
System.Web.HttpUtility.ParseQueryString(queryString)

MSDN

Evgeniy Berezovsky
  • 18,571
  • 13
  • 82
  • 156
Tejs
  • 40,736
  • 10
  • 68
  • 86
  • 29
    But you'll need to add a reference to `System.Web.dll`. – SLaks May 21 '10 at 18:28
  • 1
    As another answer say, ParseQueryString will add 'http://example.com/file?a' as the first key. – Rune Oct 25 '12 at 10:58
  • 1
    Updated with new code. Strangely enough, this answer seems to be very popular. – Tejs Nov 06 '12 at 21:47
  • One other thing to keep in mind, ParseQueryString ALWAYS does a UrlDecode when parsing, which is fine as long as you don't have anything relying on one-to-one likeness, like say a signature algorithm in a SAML Redirect binding, which calculates the signature AFTER encoding on the other side, etc. – Michael Hallock Aug 08 '13 at 20:39
  • `Split('#')[0]` will return the left side of the real or imaginary _fragment_. Here's the spec concerning placement of the _fragment_ with respect to the _query_: [RFC 3986](https://tools.ietf.org/html/rfc3986#section-4.2) – bvj May 12 '17 at 03:08
26

This should work:

string url = "http://example.com/file?a=1&b=2&c=string%20param";
string querystring = url.Substring(url.IndexOf('?'));
System.Collections.Specialized.NameValueCollection parameters = 
   System.Web.HttpUtility.ParseQueryString(querystring);

According to MSDN. Not the exact collectiontype you are looking for, but nevertheless useful.

Edit: Apparently, if you supply the complete url to ParseQueryString it will add 'http://example.com/file?a' as the first key of the collection. Since that is probably not what you want, I added the substring to get only the relevant part of the url.

pyrocumulus
  • 9,072
  • 2
  • 43
  • 53
17

I had to do this for a modern windows app. I used the following:

public static class UriExtensions
{
    private static readonly Regex _regex = new Regex(@"[?&](\w[\w.]*)=([^?&]+)");

    public static IReadOnlyDictionary<string, string> ParseQueryString(this Uri uri)
    {
        var match = _regex.Match(uri.PathAndQuery);
        var paramaters = new Dictionary<string, string>();
        while (match.Success)
        {
            paramaters.Add(match.Groups[1].Value, match.Groups[2].Value);
            match = match.NextMatch();
        }
        return paramaters;
    }
}
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
Ross Dargan
  • 5,876
  • 4
  • 40
  • 53
  • @Ross Dargan: this is a nice solution but I'd suggest creating the regex object with `RegexOptions.Compiled`, as per [this documentation](https://msdn.microsoft.com/en-us/library/8zbs0h2f%28v=vs.110%29.aspx), since it is static and intended to be reused. – easuter Feb 20 '16 at 14:48
  • I updated the regex to `@"[?&](\w[\w.]*)=([^?&]+)"` since `[|?]&` also matches `|` and `[^?|^&]` matches any char but `?` / `|` / `^` and `&`. – Wiktor Stribiżew Apr 13 '18 at 08:43
  • This throws an exception if the query parameter is used more than once. i.e. "?Arg=foo&Arg=bar" – Plater Mar 24 '23 at 16:09
14

For isolated projects, where dependencies must be kept to a minimum, I found myself using this implementation:

var arguments = uri.Query
  .Substring(1) // Remove '?'
  .Split('&')
  .Select(q => q.Split('='))
  .ToDictionary(q => q.FirstOrDefault(), q => q.Skip(1).FirstOrDefault());

Do note, however, that I do not handle encoded strings of any kind, as I was using this in a controlled setting, where encoding issues would be a coding error on the server side that should be fixed.

Johny Skovdal
  • 2,038
  • 1
  • 20
  • 36
13

Have a look at HttpUtility.ParseQueryString() It'll give you a NameValueCollection instead of a dictionary, but should still do what you need.

The other option is to use string.Split().

    string url = @"http://example.com/file?a=1&b=2&c=string%20param";
    string[] parts = url.Split(new char[] {'?','&'});
    ///parts[0] now contains http://example.com/file
    ///parts[1] = "a=1"
    ///parts[2] = "b=2"
    ///parts[3] = "c=string%20param"
3Dave
  • 28,657
  • 18
  • 88
  • 151
11

In a single line of code:

string xyz = Uri.UnescapeDataString(HttpUtility.ParseQueryString(Request.QueryString.ToString()).Get("XYZ"));
Pabinator
  • 1,601
  • 1
  • 21
  • 25
0

Microsoft Azure offers a framework that makes it easy to perform this. http://azure.github.io/azure-mobile-services/iOS/v2/Classes/MSTable.html#//api/name/readWithQueryString:completion:

Alex Bedro
  • 96
  • 7
-2

You could reference System.Web in your console application and then look for the Utility functions that split the URL parameters.

Raj
  • 1,742
  • 1
  • 12
  • 17