339

I've got a string in .NET which is actually a URL. I want an easy way to get the value from a particular parameter.

Normally, I'd just use Request.Params["theThingIWant"], but this string isn't from the request. I can create a new Uri item like so:

Uri myUri = new Uri(TheStringUrlIWantMyValueFrom);

I can use myUri.Query to get the query string...but then I apparently have to find some regexy way of splitting it up.

Am I missing something obvious, or is there no built in way to do this short of creating a regex of some kind, etc?

Syscall
  • 19,327
  • 10
  • 37
  • 52
Beska
  • 12,445
  • 14
  • 77
  • 112

17 Answers17

638

Use static ParseQueryString method of System.Web.HttpUtility class that returns NameValueCollection.

Uri myUri = new Uri("http://www.example.com?param1=good&param2=bad");
string param1 = HttpUtility.ParseQueryString(myUri.Query).Get("param1");

Check documentation at http://msdn.microsoft.com/en-us/library/ms150046.aspx

Matt Bishop
  • 1,010
  • 7
  • 18
CZFox
  • 9,015
  • 4
  • 25
  • 13
  • 17
    This doesn't seem to detect the first parameter. eg parsing "http://www.google.com/search?q=energy+edge&rls=com.microsoft:en-au&ie=UTF-8&oe=UTF-8&startIndex=&startPage=1" doesn't detect the parameter q – Andrew Shepherd Jun 30 '09 at 04:26
  • 1
    @Andrew I confirm. It's strange (bug?). You coul still use `HttpUtility.ParseQueryString(myUri.Query).Get(0)` though and it will extract first parameter. ` – Mariusz Pawelski Aug 02 '11 at 15:03
  • Any .NET tool to build a parameterized query url? – Shimmy Weitzhandler Dec 11 '11 at 15:12
  • 15
    You can't parse full query URLs with `HttpUtility.ParseQueryString(string)`! As it's name says, it's to parse Query Strings, not URLs with query parameters. If you want to do it, you must first split it by `?` like this: `Url.Split('?')` and get last element using (depending on situation and what you need) `[0]` or LINQ's `Last()` / `LastOrDefault()`. – Kosiek Jan 16 '18 at 11:50
  • 1
    When trialling this myself, the signature appears to have changed to this: HttpUtility.ParseQueryString(uri.Query).GetValues("param1").First() – The Senator Feb 21 '18 at 18:48
  • Severity Code Description Project File Line Suppression State Error CS0234 The type or namespace name 'HttpUtility' does not exist in the namespace 'System.Web' (are you missing an assembly reference?) – Dmitry Sokolov Nov 23 '20 at 15:52
  • This is not working properly in my case I have a query. I have URL "https://test.com/page?time=2022031&&user=test+2fa@gmail.com". And I am trying to fetch "user" querystring. The result return by this approach is "test 2fa@gmail.com" i.e. it's removing the + sign from the user name. Any idea why it's not working – Ashish Shukla Mar 24 '21 at 05:42
  • 1
    @AshishShukla: It url encoding, `[space]` -> `+`. Then `HttpUtility.ParseQueryString` decoding it – Trương Quốc Khánh Aug 08 '22 at 18:04
  • @DmitrySokolov you need to add a reference to `System.Web`, then you can add `using System.Web` and access the function in your code with `HttpUtility.ParseQueryString`. – Tim Oct 21 '22 at 14:02
60

This is probably what you want

var uri = new Uri("http://domain.test/Default.aspx?var1=true&var2=test&var3=3");
var query = HttpUtility.ParseQueryString(uri.Query);

var var2 = query.Get("var2");
Sergej Andrejev
  • 9,091
  • 11
  • 71
  • 108
44

Here's another alternative if, for any reason, you can't or don't want to use HttpUtility.ParseQueryString().

This is built to be somewhat tolerant to "malformed" query strings, i.e. http://test/test.html?empty= becomes a parameter with an empty value. The caller can verify the parameters if needed.

public static class UriHelper
{
    public static Dictionary<string, string> DecodeQueryParameters(this Uri uri)
    {
        if (uri == null)
            throw new ArgumentNullException("uri");

        if (uri.Query.Length == 0)
            return new Dictionary<string, string>();

        return uri.Query.TrimStart('?')
                        .Split(new[] { '&', ';' }, StringSplitOptions.RemoveEmptyEntries)
                        .Select(parameter => parameter.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries))
                        .GroupBy(parts => parts[0],
                                 parts => parts.Length > 2 ? string.Join("=", parts, 1, parts.Length - 1) : (parts.Length > 1 ? parts[1] : ""))
                        .ToDictionary(grouping => grouping.Key,
                                      grouping => string.Join(",", grouping));
    }
}

Test

[TestClass]
public class UriHelperTest
{
    [TestMethod]
    public void DecodeQueryParameters()
    {
        DecodeQueryParametersTest("http://test/test.html", new Dictionary<string, string>());
        DecodeQueryParametersTest("http://test/test.html?", new Dictionary<string, string>());
        DecodeQueryParametersTest("http://test/test.html?key=bla/blub.xml", new Dictionary<string, string> { { "key", "bla/blub.xml" } });
        DecodeQueryParametersTest("http://test/test.html?eins=1&zwei=2", new Dictionary<string, string> { { "eins", "1" }, { "zwei", "2" } });
        DecodeQueryParametersTest("http://test/test.html?empty", new Dictionary<string, string> { { "empty", "" } });
        DecodeQueryParametersTest("http://test/test.html?empty=", new Dictionary<string, string> { { "empty", "" } });
        DecodeQueryParametersTest("http://test/test.html?key=1&", new Dictionary<string, string> { { "key", "1" } });
        DecodeQueryParametersTest("http://test/test.html?key=value?&b=c", new Dictionary<string, string> { { "key", "value?" }, { "b", "c" } });
        DecodeQueryParametersTest("http://test/test.html?key=value=what", new Dictionary<string, string> { { "key", "value=what" } });
        DecodeQueryParametersTest("http://www.google.com/search?q=energy+edge&rls=com.microsoft:en-au&ie=UTF-8&oe=UTF-8&startIndex=&startPage=1%22",
            new Dictionary<string, string>
            {
                { "q", "energy+edge" },
                { "rls", "com.microsoft:en-au" },
                { "ie", "UTF-8" },
                { "oe", "UTF-8" },
                { "startIndex", "" },
                { "startPage", "1%22" },
            });
        DecodeQueryParametersTest("http://test/test.html?key=value;key=anotherValue", new Dictionary<string, string> { { "key", "value,anotherValue" } });
    }

    private static void DecodeQueryParametersTest(string uri, Dictionary<string, string> expected)
    {
        Dictionary<string, string> parameters = new Uri(uri).DecodeQueryParameters();
        Assert.AreEqual(expected.Count, parameters.Count, "Wrong parameter count. Uri: {0}", uri);
        foreach (var key in expected.Keys)
        {
            Assert.IsTrue(parameters.ContainsKey(key), "Missing parameter key {0}. Uri: {1}", key, uri);
            Assert.AreEqual(expected[key], parameters[key], "Wrong parameter value for {0}. Uri: {1}", parameters[key], uri);
        }
    }
}
alsed42
  • 1,196
  • 7
  • 10
  • helpful for Xamarin project, where HttpUtility is unavailable – Artemious Jul 28 '19 at 21:44
  • That's a very useful extension that can be adapted for partial URIs, as well. I'd suggest adding a Uri.UnescapeDataString() to the parameter values or rename the method to something other than "decode" if they aren't actually decoded. `?empty=` isn't a malformed query string. It just has a parameter with an empty string as the value. That's completely normal, so thanks for taking that into account. – Suncat2000 Jan 14 '21 at 11:57
  • This does not match the behavior of `HttpUtility.ParseQueryString()` because it does not perform proper decoding of the values. As noted in the expected result test cases `{ "startPage", "1%22" }` the value is still percent encoded but would be `1"` if it was parsed by HttpUtility class. – CajunCoding Apr 05 '21 at 20:12
17

Looks like you should loop over the values of myUri.Query and parse it from there.

 string desiredValue;
 foreach(string item in myUri.Query.Split('&'))
 {
     string[] parts = item.Replace("?", "").Split('=');
     if(parts[0] == "desiredKey")
     {
         desiredValue = parts[1];
         break;
     }
 }

I wouldn't use this code without testing it on a bunch of malformed URLs however. It might break on some/all of these:

  • hello.html?
  • hello.html?valuelesskey
  • hello.html?key=value=hi
  • hello.html?hi=value?&b=c
  • etc
Alex from Jitbit
  • 53,710
  • 19
  • 160
  • 149
Tom Ritter
  • 99,986
  • 30
  • 138
  • 174
15

@Andrew and @CZFox

I had the same bug and found the cause to be that parameter one is in fact: http://www.example.com?param1 and not param1 which is what one would expect.

By removing all characters before and including the question mark fixes this problem. So in essence the HttpUtility.ParseQueryString function only requires a valid query string parameter containing only characters after the question mark as in:

HttpUtility.ParseQueryString ( "param1=good&param2=bad" )

My workaround:

string RawUrl = "http://www.example.com?param1=good&param2=bad";
int index = RawUrl.IndexOf ( "?" );
if ( index > 0 )
    RawUrl = RawUrl.Substring ( index ).Remove ( 0, 1 );

Uri myUri = new Uri( RawUrl, UriKind.RelativeOrAbsolute);
string param1 = HttpUtility.ParseQueryString( myUri.Query ).Get( "param1" );`
SharpC
  • 6,974
  • 4
  • 45
  • 40
Mo Gauvin
  • 159
  • 2
  • 4
  • When the URI is instantiated I get the error "Invalid URI: The format of the URI could not be determined." I don't think this solution works as intended. – Paul Matthews Nov 11 '13 at 23:17
  • @PaulMatthews, you are correct. At the time of this given solution, I was using the older .net framework 2.0. To confirm, your statement, I copied and pasted this solution into LINQPad v2 by Joseph Albahara and received the same error you mentioned. – Mo Gauvin Nov 12 '13 at 22:18
  • @PaulMatthews, To fix, remove the line that reads Uri myUri = new Uri( RawUrl ); and merely pass RawUrl to the last statement as in: string param1 = HttpUtility.ParseQueryString( RawUrl ).Get( "param2" ); – Mo Gauvin Nov 12 '13 at 22:25
  • Yeah, the fact that it parses only the query string part is in the name and in the documentation. It's not a bug. I'm not even sure how they could make it any clearer. `ParseQueryString` parses query strings. – PandaWood Jan 27 '20 at 23:00
8

You can just use the Uri to get the list of the query strings or find a specific parameter.

Uri myUri = new Uri("http://www.example.com?param1=good&param2=bad");
var params = myUri.ParseQueryString();
var specific = myUri.ParseQueryString().Get("param1");
var paramByIndex = myUri.ParseQueryString().Get(2);

You can find more from here: https://learn.microsoft.com/en-us/dotnet/api/system.uri?view=net-5.0

Amintabar
  • 2,198
  • 1
  • 29
  • 29
5

You can use the following workaround for it to work with the first parameter too:

var param1 =
    HttpUtility.ParseQueryString(url.Substring(
        new []{0, url.IndexOf('?')}.Max()
    )).Get("param1");
tomsv
  • 7,207
  • 6
  • 55
  • 88
2

Or if you don't know the URL (so as to avoid hardcoding, use the AbsoluteUri

Example ...

        //get the full URL
        Uri myUri = new Uri(Request.Url.AbsoluteUri);
        //get any parameters
        string strStatus = HttpUtility.ParseQueryString(myUri.Query).Get("status");
        string strMsg = HttpUtility.ParseQueryString(myUri.Query).Get("message");
        switch (strStatus.ToUpper())
        {
            case "OK":
                webMessageBox.Show("EMAILS SENT!");
                break;
            case "ER":
                webMessageBox.Show("EMAILS SENT, BUT ... " + strMsg);
                break;
        }
Fandango68
  • 4,461
  • 4
  • 39
  • 74
2

Use .NET Reflector to view the FillFromString method of System.Web.HttpValueCollection. That gives you the code that ASP.NET is using to fill the Request.QueryString collection.

SharpC
  • 6,974
  • 4
  • 45
  • 40
David
  • 34,223
  • 3
  • 62
  • 80
2

Single line LINQ solution:

Dictionary<string, string> ParseQueryString(string query)
{
    return query.Replace("?", "").Split('&').ToDictionary(pair => pair.Split('=').First(), pair => pair.Split('=').Last());
}
Spirit
  • 61
  • 2
1

Here is a sample that mentions what dll to include

var testUrl = "https://www.google.com/?q=foo";

var data = new Uri(testUrl);

// Add a reference to System.Web.dll
var args = System.Web.HttpUtility.ParseQueryString(data.Query);

args.Set("q", "my search term");

var nextUrl = $"{data.Scheme}://{data.Host}{data.LocalPath}?{args.ToString()}";
John
  • 5,942
  • 3
  • 42
  • 79
0

if you want in get your QueryString on Default page .Default page means your current page url . you can try this code :

string paramIl = HttpUtility.ParseQueryString(this.ClientQueryString).Get("city");
Erhan Demirci
  • 4,173
  • 4
  • 36
  • 44
0

This is actually very simple, and that worked for me :)

        if (id == "DK")
        {
            string longurl = "selectServer.aspx?country=";
            var uriBuilder = new UriBuilder(longurl);
            var query = HttpUtility.ParseQueryString(uriBuilder.Query);
            query["country"] = "DK";

            uriBuilder.Query = query.ToString();
            longurl = uriBuilder.ToString();
        } 
Ralle12
  • 15
  • 5
0

For anyone who wants to loop through all query strings from a string

        foreach (var item in new Uri(urlString).Query.TrimStart('?').Split('&'))
        {
            var subStrings = item.Split('=');

            var key = subStrings[0];
            var value = subStrings[1];

            // do something with values
        }
Indy411
  • 3,666
  • 4
  • 20
  • 19
0

In .NET 7

var uri = new Uri("http://example.com/?var1=true&var2=test&var3=3");
var query = HttpUtility.ParseQueryString(uri.Query);
var var1 = query.Get("var1");
Jamalien
  • 1
  • 1
0

If you're in the context of an HttpRequest and using ASPNET core, it can be as simple as Request.Query["paramName"]

I'm not sure when this was added though.

Jamal Salman
  • 199
  • 1
  • 10
-1

Easiest way how to get value of know the param name:

using System.Linq;
string loc = "https://localhost:5000/path?desiredparam=that_value&anotherParam=whatever";

var c = loc.Split("desiredparam=").Last().Split("&").First();//that_value
Alamakanambra
  • 5,845
  • 3
  • 36
  • 43