Stephen Sulzberger’s Blog

January 20, 2008

asp.net: Modify Request.QueryString

Filed under: .net, C#, asp.net — Stephen @ 4:30 pm

Suppose you needed to modify the query string passed in a given URL before redirecting to another (or even the same) page. For example, imagine you needed to take:

/default.aspx?name1=value1&name2=value2&color=red

and turn it into something like:

/default.aspx?name1=valueX&name2=valueY&colorcode=red

I’ve seen this done with loops, new URI’s, and so on to get around the query string read-only “problem”, but most implementations like these are fairly arduous, not to mention error-prone. Given all of the idiosyncrasies involved with the Request.QueryString object (e.g. is read-only, is a modified version of the NameValueCollection object, etc.), I still think the the following approach is the best bet:

using System.Collections.Specialized;

public partial class ModifyQueryStringExample : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
    // Create a new (editable) NameValueCollection using the existing (read-only) collection
    NameValueCollection objNewValueCollection = HttpUtility.ParseQueryString(Request.QueryString.ToString());
    objNewValueCollection.Set("name1", "valueX");
    objNewValueCollection.Set("name2", "valueY");
    objNewValueCollection.Add("colorcode", objNewValueCollection.Get("color"));
    objNewValueCollection.Remove("color");

    string sRedirect = Request.Url.AbsolutePath;
    string sNewQueryString = "?" + objNewValueCollection.ToString();

    sRedirect = sRedirect + sNewQueryString;

    Response.Redirect(sRedirect, true);
  }
}

Some notes:

  1. All other parameters passed in by the original query string will be carried over untouched. For example, if the original query string also included something like “id=1234&status=1″, these values would persist into the new redirect even while the other name/value pairs have been modified.    
  2. The NameValueCollection Set() method allows nulls, so it will work regardless of whether or not the key you’re looking for actually exists. If the key exists, the value will be appended accordingly. If the key does not exist, it will be added with the appropriate value. This time around I chose to use the Add() method for readability since I know for a fact that this routine will always be adding a key (“colorcode”) rather than appending one.

  3. All NameValueCollection methods that use a text compare are case-insensitive, as per msdn: http://msdn2.microsoft.com/en-us/library/system.collections.specialized.namevaluecollection.namevaluecollection.aspx 
  4. The NameValueCollection ToString() method automatically inserts “=”/”&” characters for you when/where appropriate. The NameValueCollection instance returned by HttpUtility.ParseQueryString is an HTTPValueCollection (a specialized NameValueCollection type), so its ToString() method will automatically insert “=”/”&” characters for you where appropriate. Although this is undoubtedly a nice feature, one can’t help but mention that the surprisingly convenient behavior just described is not immediately obvious given the msdn documentation at http://msdn.microsoft.com/en-us/library/system.web.httputility.parsequerystring.aspx. Nevertheless, the implementation is made clear by evaluating any NameValueCollection.ToString() against an HTTPValueCollection.ToString(). The former will return the object’s string representation (‘System.Collections.Specialized.NameValueCollection’) while the latter, of course, will provide a legitimate name/value collection with the applicable field-value separators. Interestingly, the only way to get an HTTPValueCollection instance in the first place is to use HttpUtility.ParseQueryString. No doubt a quirky matter. For further discussion on the issue, visit http://msmvps.com/blogs/paulomorgado/archive/2008/07/15/make-the-httpvaluecollection-class-public-and-move-it-to-system-dll.aspx               

9 Comments »

  1. hi ;)

    statement 4 is not quite correct.
    actually, HttpUtility.ParseQueryString creates a HTTPValueCollection, rather than NameValueCollection, and the insertion of “=” and “&” is only implemented in the HTTPValueCollection.ToString()

    I just ran into this, so I thought I let you know.

    Comment by devio — March 28, 2008 @ 4:17 am | Reply

  2. Thanks devio!

    Comment by Stephen — April 4, 2008 @ 6:22 pm | Reply

  3. Somehow i missed the point. Probably lost in translation :) Anyway … nice blog to visit.

    cheers, Cajolingly.

    Comment by Cajolingly — June 18, 2008 @ 5:14 pm | Reply

  4. NameValueCollection is the type that the HttpUtility.ParseQueryString returns not a HTTPValueCollection.

    Awesome code, and for those lost in translation. Access to the QS collection through code is a very good thing for those who create controls dynamically and need access to server sided events.

    Here is your code made into a class file. Tested and working.

    Reqs.= web.httpcontext.current

    Public Class TsQueryString
    Private QVal As NameValueCollection

    Public Sub New()
    QVal = HttpUtility.ParseQueryString(Current.Request.QueryString.ToString())
    End Sub

    Public Sub AppendQueryString(ByVal Key As String, ByVal Value As String)
    QVal.Add(Key, Value)
    End Sub

    Public Sub removeQueryString(ByVal Key As String)
    QVal.Remove(Key)
    End Sub

    Public Function GetQueryString() As String
    Return QVal.ToString
    End Function

    Public Function RedirectURL(ByVal UrlPath As String) As String
    Return (UrlPath & “?” & GetQueryString())
    End Function

    Public ReadOnly Property GetURL() As String
    Get
    Return Current.Request.Url.AbsolutePath
    End Get
    End Property

    End Class

    Comment by TribalStone — September 13, 2008 @ 2:08 pm | Reply

  5. Very helpful article, I came across the problem of trying to make a copy of the QueryString in a new NameValueCollection, initializing it from the QueryString directly, and found that the ToString() method indeed returned ’System.Collections.Specialized.NameValueCollection’ in stead of something that could be used as a query string.
    I think Microsoft should point out explitly that the HttpUtility.ParseQueryString method returns a HTTPValueCollection in their documentation.

    Great work! :-)

    Comment by Jacob Coens — October 3, 2008 @ 2:29 am | Reply

  6. I’m frustrated with NameValueCollection. It doesn’t have a sensible ToString, it isn’t XMLSerializable, and it doesn’t have a constructor that takes input other than another NameValueCollection (taking a hash or an array to start with would help me greatly). I can CopyTo an array, but not in the other direction. I’m going to have to write my own helper utility methods in my code just to convert to and from a format I can easily store. :( Grumble, Grumble Microsoft.

    Comment by Joseph — October 31, 2008 @ 10:27 am | Reply

  7. Very elegant and useful script, Stephen, thank you for posting. I think it would be even more useful if the query string values could be conditionally changed. That is, If name1 = value1, assign valueX, or if name1 = value2, assign valueXX or if name1 = value3, assign valueXXX. You know what I mean. I would love to see how the script could be modified to accomplish that. Unfortunately, this is beyond my abilities.

    Comment by Michael — November 1, 2008 @ 10:21 am | Reply

  8. Hi! I was surfing and found your blog post… nice! I love your blog. :) Cheers! Sandra. R.

    Comment by sandrar — September 10, 2009 @ 5:48 am | Reply

  9. To use the very useful .ToString() method of the HttpValueCollection, do this:

    NameValueCollection nvc = HttpUtility.ParseQueryString(“”);

    nvc["a"] = “123″;
    nvc["b"] = “456″;

    Debug.WriteLine(nvc.ToString());

    // Returns a=123&b=456

    Comment by Alan Singfield — November 20, 2009 @ 1:48 am | Reply


RSS feed for comments on this post. TrackBack URI

Leave a comment

Blog at WordPress.com.