ASP.NET Params Collection vs. QueryString, Forms vs. Request["index"] and Double Decoding
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:
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.
About Newsletter
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
Not sure why I didn't just always use querystring.
Comments are closed.
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