How to efficiently remove a query string by Key from a Url?

75,977

Solution 1

This works well:

public static string RemoveQueryStringByKey(string url, string key)
{                   
    var uri = new Uri(url);

    // this gets all the query string key value pairs as a collection
    var newQueryString = HttpUtility.ParseQueryString(uri.Query);

    // this removes the key if exists
    newQueryString.Remove(key);

    // this gets the page path from root without QueryString
    string pagePathWithoutQueryString = uri.GetLeftPart(UriPartial.Path);

    return newQueryString.Count > 0
        ? String.Format("{0}?{1}", pagePathWithoutQueryString, newQueryString)
        : pagePathWithoutQueryString;
}

an example:

RemoveQueryStringByKey("https://www.google.co.uk/search?#hl=en&output=search&sclient=psy-ab&q=cookie", "q");

and returns:

https://www.google.co.uk/search?#hl=en&output=search&sclient=psy-ab

Solution 2

    var queryString = "hello=hi&xpid=4578";
    var qs = System.Web.HttpUtility.ParseQueryString(queryString);
    qs.Remove("xpid");
    var newQuerystring = qs.ToString();

This still works in .NET 5.

Solution 3

There's a useful class called UriBuilder in the System namespace. We can use it along with a couple of extension methods to do the following:

Uri u = new Uri("http://example.com?key1=value1&key2=value2");
u = u.DropQueryItem("key1");

Or like this:

Uri u = new Uri("http://example.com?key1=value1&key2=value2");
UriBuilder b = new UriBuilder(u);
b.RemoveQueryItem("key1");
u = b.Uri;

The extension methods:

using System;
using System.Collections.Specialized;
using System.Text;
using System.Text.RegularExpressions;

public static class UriExtensions
{
    public static Uri DropQueryItem(this Uri u, string key)
    {
        UriBuilder b = new UriBuilder(u);
        b.RemoveQueryItem(key);
        return b.Uri;
    }
}
public static class UriBuilderExtensions
{
    private static string _ParseQueryPattern = @"(?<key>[^&=]+)={0,1}(?<value>[^&]*)";
    private static Regex _ParseQueryRegex = null;

    private static Regex ParseQueryRegex
    {
        get
        {
            if (_ParseQueryRegex == null)
            {
                _ParseQueryRegex = new Regex(_ParseQueryPattern, RegexOptions.Compiled | RegexOptions.Singleline);
            }
            return _ParseQueryRegex;

        }
    }

    public static void SetQueryItem(this UriBuilder b, string key, string value)
    {
        NameValueCollection parms = ParseQueryString(b.Query);
        parms[key] = value;
        b.Query = RenderQuery(parms);
    }

    public static void RemoveQueryItem(this UriBuilder b, string key)
    {
        NameValueCollection parms = ParseQueryString(b.Query);
        parms.Remove(key);
        b.Query = RenderQuery(parms);
    }       
    private static string RenderQuery(NameValueCollection parms)
    {
        StringBuilder sb = new StringBuilder();
        for (int i=0; i<parms.Count; i++)
        {
            string key = parms.Keys[i];
            sb.Append(key + "=" + parms[key]);
            if (i < parms.Count - 1)
            {
                sb.Append("&");
            }
        }
        return sb.ToString();
    }
    public static NameValueCollection ParseQueryString(string query, bool caseSensitive = true)
    {
        NameValueCollection pairs = new NameValueCollection(caseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase);

        string q = query.Trim().TrimStart(new char[] {'?'});
        MatchCollection matches = ParseQueryRegex.Matches(q);

        foreach (Match m in matches)
        {
            string key = m.Groups["key"].Value;
            string value = m.Groups["value"].Value;
            if (pairs[key] != null)
            {
                pairs[key] = pairs[key] + "," + value;
            }
            else
            {
                pairs[key] = value;
            }

        }

        return pairs;

    }

}

Solution 4

We can also do it using regex

string queryString = "Default.aspx?Agent=10&Language=2"; //Request.QueryString.ToString();
string parameterToRemove="Language";   //parameter which we want to remove
string regex=string.Format("(&{0}=[^&\s]+|(?<=\?){0}=[^&\s]+&?)",parameterToRemove);   //this will not work for javascript, for javascript you can do following
string finalQS = Regex.Replace(queryString, regex, "");

//javascript(following is not js syntex, just want to give idea how we can able do it in js)
string regex1 = string.Format("(&{0}=[^&\s]+)",parameterToRemove);
string regex2 = string.Format("(\?{0}=[^&\s]+&?)",parameterToRemove);
string finalQS = Regex.Replace(queryString, regex1, "").Replace(queryString, regex2, "");

https://regexr.com/3i9vj

Solution 5

I know this is a rather old question, but everything I read felt a bit complicated.

public Uri GetUriWithoutQueryParam( Uri originalUri, string paramKey ) {
  NameValueCollection newQuery = HttpUtility.ParseQueryString( originalUri.Query );
  newQuery.Remove( paramKey );
  return new UriBuilder( originalUri ) { Query = newQuery.ToString() }.Uri;
}
Share:
75,977
The Light
Author by

The Light

I love thinking and writing .NET applications and have over 13 years experience + MCPD, MCTS, MCAD, MCP.

Updated on July 24, 2022

Comments

  • The Light
    The Light almost 2 years

    How to remove a query string by Key from a Url?

    I have the below method which works fine but just wondering is there any better/shorter way? or a built-in .NET method which can do it more efficiently?

     public static string RemoveQueryStringByKey(string url, string key)
            {
                var indexOfQuestionMark = url.IndexOf("?");
                if (indexOfQuestionMark == -1)
                {
                    return url;
                }
    
                var result = url.Substring(0, indexOfQuestionMark);
                var queryStrings = url.Substring(indexOfQuestionMark + 1);
                var queryStringParts = queryStrings.Split(new [] {'&'});
                var isFirstAdded = false;
    
                for (int index = 0; index <queryStringParts.Length; index++)
                {
                    var keyValue = queryStringParts[index].Split(new char[] { '=' });
                    if (keyValue[0] == key)
                    {
                        continue;
                    }
    
                    if (!isFirstAdded)
                    {
                        result += "?";
                        isFirstAdded = true;
                    }
                    else
                    {
                        result += "&";
                    }
    
                    result += queryStringParts[index];
                }
    
                return result;
            }
    

    For example I can call it like:

      Console.WriteLine(RemoveQueryStringByKey(@"http://www.domain.com/uk_pa/PostDetail.aspx?hello=hi&xpid=4578", "xpid"));
    

    Hope the question is clear.

    Thanks,

  • rahularyansharma
    rahularyansharma about 11 years
    string doesnt contain defination for FormatWith method
  • NickG
    NickG almost 11 years
    Is there a way to do this without using FormatWith? That's not available in .NET 4.0
  • Mattias Örtenblad
    Mattias Örtenblad over 6 years
    This works if the url has protocol. The Uri constructor throws if it's missing. i.e. new Uri("stackoverflow.com") - works but new Uri("stackoverflow.com") does not.
  • Pavel
    Pavel about 6 years
    Not processed case when no query
  • freefaller
    freefaller over 5 years
    Unfortunately your pattern also picks up "end of" matching on the first item (e.g. change parameterToRemove="ent" an you'll end up with Default.aspx?AgLanguage=2). If you don't have to support javascript, the following amendment uses positive-lookbehind to get around this: (&{0}=[^&\s]+|(?<=\?){0}=[^&\s]+&?)
  • Morgeth888
    Morgeth888 over 5 years
    UriBuilder' does not contain a definition for 'RemoveQueryItem' and no accessible extension method 'RemoveQueryItem' accepting a first argument of type 'UriBuilder' could be found (are you missing a using directive or an assembly reference?) on 4.6 dotnet version
  • Morgeth888
    Morgeth888 over 5 years
    Those of you mentioning the invalid format issue, you are more than likely already dealing with a URI perhaps. You can simply change this method to accept the Uri instead of the string url. Then you simply delete the line creating one from the string.
  • Steve Lautenschlager
    Steve Lautenschlager over 5 years
    @TommyHolman Sorrry about that. It turns out RemoveQueryItem was my own extension method on UriBuilder. I've updated my answer to include it.
  • Qin Chao
    Qin Chao over 4 years
    This answer missed Uri.Fragment (the hash #xxx) handling. So the URL like "google.co.uk/…" will losethe "#xxx" after processing. So the returned value should add uri.Fragment
  • Cesar
    Cesar about 3 years
    This solution is cool because the Remove() method actually works.