Scott Hanselman

ASP.NET Params Collection vs. QueryString, Forms vs. Request["index"] and Double Decoding

December 17, 2004 Comment on this post [4] Posted in ASP.NET
Sponsored By

In ASP.NET you can yank a value out of the QueryString like this, where QueryString is of type NameValueCollection but is internally an HttpValueCollection that includes some extra helper methods.

string foo = Request.QueryString["foo"];

But you can also go like this:

string foo = Request["foo"];

And folks know (passed through myth and legend) that the line above will search through the QueryString, Form, Cookies, and ServerVariables collections. However, it's important (for performance) to know what order the collections are searched. Here's the code from Reflector:  

    1 public string get_Item(string key)
    2 {
    3     string text1 = this.QueryString[key];
    4     if (text1 != null)
    5     {
    6         return text1;
    7     }
    8     text1 = this.Form[key];
    9     if (text1 != null)
   10     {
   11         return text1;
   12     }
   13     HttpCookie cookie1 = this.Cookies[key];
   14     if (cookie1 != null)
   15     {
   16         return cookie1.Value;
   17     }
   18     text1 = this.ServerVariables[key];
   19     if (text1 != null)
   20     {
   21         return text1;
   22     }
   23     return null;
   24 }

So you can see what order things are searched in. However, personally, I don't like this default Item indexer. I prefer to be more explicit. I'd hate to accidentally retrieve a Cookie because a QueryString variable was missing. It's always better to be explicit and ask for what you want.

Interestingly, there is ANOTHER collection of QueryString, Form, Cookies, and ServerVariables, but rather than a "pseudo-collection" as we see above, this is an actual combined collection.

  432 public NameValueCollection Params
433 {
434 get
435 {
436 InternalSecurityPermissions.AspNetHostingPermissionLevelLow.Demand();
437 if (this._params == null)
438 {
439 this._params = new HttpValueCollection();
440 this.FillInParamsCollection();
441 this._params.MakeReadOnly();
442 }
443 return this._params;
444 }
445 }
446
447 private void FillInParamsCollection()
448 {
449 this._params.Add(this.QueryString);
450 this._params.Add(this.Form);
451 this._params.Add(this.Cookies);
452 this._params.Add(this.ServerVariables);
453 }
454

The internal collection "_params" inside is a special derived NameValueCollection of type HttpValueCollection, and is exposed as NameValueCollection.

Important Note: The constructor for HttpRequest will parse the actual string QueryString and UrlDecode the values for you. Be careful not to DOUBLE DECODE. Know what's encoded, when, and who does the decoding.  Likely it's not you that needs to do anything. If you double decode you can get into some weird situations. Ben Suter reminded me that if you pass in /somepage.aspx?someParam=A%2bB you expect to get "A+B" as that param is the equivalent of HttpUtility.UrlEncode("A+B"). But, if you make a mistake and do HttpUtility.UrlDecode(Request.Params("someParam")), you'll get "A B" as the + was double-decoded as a space.

Here's the trick though. If you have BOTH a QueryString parameter "Foo=Bar1" AND a Forms item called "Foo=Bar2" if you say string foo = Request.Params["Foo"]; you'll get a string back "Bar1,Bar2"! It's a collection, not a HashTable. So, never make assumptions when you use HttpRequest.Params, or you will get in trouble. If there's a chance you could get multiple values back, you need to consider using an explicit collection or be smart about your string.Split() code.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service
December 17, 2004 19:42
Thanks Scott,

I am in the bad habit of always using params (because I thought it was cool) vs the specific collection so I will now think twice before I use it again.

Keep up the good work.

Stephen
July 19, 2005 16:20
Dear Scott,

I had a trouble with QueryString. I had a '+' in the QueryString which was missing while getting the value from another page. After using HttpUtility.UrlEncode() the problem solved. Thank you very much.

Raihan
July 20, 2005 5:18
If I add a value using Request.Params.Add() method, what is the lifespan of that? I know Request.Context.Items lasts the duration of a Request's execution. Is this true for Params?
August 01, 2005 21:49
Thank you. This solved a problem that I've been living with for over a year. Using Params I kept getting a trailing comma added to my parameter that I had to remove with an ugly line of code. Now I see it was because I had a page variable by the same name that was null at the time the param string was passed.

Not sure why I didn't just always use querystring.

Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.