This tip was submitted to the Visual Studio .NET Info Center Tip Exchange by member Roger McCook. Let other users know how useful it is by rating the tip below. Got a tip or code of your own you'd like to share? Submit it here.
This article provides specific instructions on using cookies in ASP.NET applications and discusses a few issues we should be thinking about when using them.
A cookie is used to store user-specific information such as a nick name or preference. The cookie may be persistent (written to the user's hard disk) or non-persistent. A non-persistent cookie exists during the life of the user's session and is then discarded. The only difference between the two types is that a persistent cookie has an expiration date, a non-persistent cookie does not.
A cookie is a small bit of text that attaches itself to requests which are traveling back and forth between the web server and the user's browser. The important properties of a cookie are (1) cookie name, (2) cookie value and (3) expiration date. The cookie's name is how you identify the cookie. The cookie's value is the information that the cookie contains. Whenever you type a URL into your browser, the browser checks to see if there are any cookies on your machine associated with that site. If there are no cookies, the request is sent without cookies. If there are cookies but they have expired, the cookie is automatically deleted. If there are cookies which have not expired, they get attached to the request and are sent along.
There are some limitations you should be concerned about. Most browsers limit cookies to 4096 bytes. Also there is usually a limit of 20 cookies per site and an overall limit of 300 cookies from all sites combined. Exceed these last two limits and the oldest cookies start dropping off behind the refrigerator where they will surely attract bugs.
Let's say, for instance, that you are working on a corporate intranet where the site name is http://BugCompany.com. You may have any number of applications. Each application is usually a separate real or virtual folder under your root directory. You might have a few problems here. First, there is the limit of 20 cookies for all your applications, since they are all the same site. The limit does not refer to different applications at a site but to the entire site taken as a whole. Next let's say that two or more applications write a cookie with the same name. In that case, each application will overwrite the cookie created by the other application. This may or may not be a problem. If this cookie is used for the same purpose in every applications, that is not a problem. If one application is expecting the cookie to be a string like 'Mr Jones' and another application is expecting a string representation of a number such as '4924', you may get unpredictable results or application errors. You could use a naming convention such as the appName.CookieName, which would help prevent cookies from accidentally overwriting each other, but then you'd still have the problem of the 20-cookie limit, and you might actually want a cookie with a given name to apply to all applications. Well, you see the problems. How you solve them depends on your own particular situation. Understanding the problem is half the battle.
Reading a cookie
The following is an example of how a function can return a cookie value. In this case, the function returns the value of the cookie, if it exists, and zero if it doesn't. This function would be on a page, not in a module.
Private Function GetManagerCookie() As String Dim strReturnValue As String = "0" If Not Request.Cookies("MgrID") Is Nothing Then Dim Cookie As HttpCookie = Request.Cookies("MgrID") If IsNumeric(Cookie.Value) = True Then strReturnValue = Cookie.Value End If Return strReturnValue End Function
From the above snippet, you can see that I'm looking for a manger ID (an integer). Of course, all cookies are stored as strings, so I'm going to get the string and convert it to a numeric value after I get it from this function. First, I set the strReturnValue to "0," which is the default value I will return. Next I test to make sure the cookie exists before I grab its value -- otherwise I'd have a null reference exception and my application would probably crash. Next, if the cookie exists, I'm making sure that it is numeric before I grab the value, because I am only looking for a numeric value, not some string value from some other cookie with the same name. Lastly, I return strReturnValue from the function.
The above discussion leads me to a couple of rules you might want to follow:
- Make sure the cookie exists (is not nothing) before trying to refer to its value property. Otherwise you'll error out with a null reference exception. There are different reasons why a cookie may not exist. (a) It was never created in the first place. (b) It was created but was deleted by the user. (c) It got removed because there were too many cookies. (d) The user has turned off cookies in the browser options. (e) The browser does not support cookies. The only way I know to determine if the user has cookies turned off is to write a procedure that will create a small, non-persistent cookie, then try to read it from another page. You'll have to tinker around with this or find an example out on the Web somewhere.
- Be suspicious of the information you get out of the cookie, if it does exist. If it is supposed to be numeric, test it out. You might also want to sanitize the value by using: Server.HTMLEncode(Cookie.Value) if you think there may be weird stuff in there.
Writing a cookie
Here is an example of a procedure that will write a cookie. Again, this procedure would exist on a Web page, not in a separate module.
Private Sub SaveManagerCookie(ByVal strCookieValue as String) Dim Cookie As New HttpCookie("MgrID") Cookie.Value = strCookieValue Cookie.Expires = #12/31/2099# Response.AppendCookie(Cookie) End Sub.
- I'm passing in the value (strCookieValue) that I want to save.
- I'm assigning an expiration date far into the distant future. There was nothing magic about this date except I expect to be dead by then. The existence of an expiration date means that the cookie is persistent (will be written to the user's PC). If there is no expiration date, the cookie will be not persist. The expiration date has limited value other than helping the application figure out how to use it. You can't read the date of an expired cookie because an expired cookie is automatically deleted and you'll never see it at all! The browser does not actually include the expiration date in the information it sends, so if you try to read the expiration date of a cookie, all you get is the datetime value of zero -- not very useful.
- To edit a cookie, just change the value (contents) or expiration date and the cookie gets overwritten.
- To delete a cookie from a user's machine, set the expiration date to some date prior to today -- then the browser will delete it for you automatically.
Where are all my cookies?
I'm using Windows XP and I find my cookies in: c:Documents and Settings\<user>\Cookies, where <user> is the login name of the current user. If you want to view your cookies (and who doesn't?), you can do it from Internet Explorer. Select Tools, Internet Options. On the General tab, click the 'Settings' button, then click the 'View Files' button. The cookies are the files which start with "cookie:". I see entries on my machine like:
Users can easily delete all their cookies. All they have to do (in Internet Explorer), is click on Tools, Internet Options. On the general tab, click the 'Delete Cookies' button. This means that we programmers can never depend on a cookie being present. We have to test for existence.
Now that you know where the cookies are, you can probably figure out how to read what's in there. Just open the file with Notepad and start reading. If this doesn't sound very secure to you, then don't put secrets (passwords, sensitive credit information) into cookies unless you can encrypt the information. Cookie encryption is way beyond the scope of this article. Another note: You shouldn't try to change a cookie entry using an editor such as Notepad. There is a checksum in the file that will detect the change and invalidate the cookie anyway.
How can I eat my cookies?
Hey, come on, man! I'm trying to write a serious technical article here. Give me a break.
I'm not going to get too far into the detail of cookie scope except to mention it. You can limit a cookie to a certain application or directory by specifying the path property for the cookie. For example: Cookie.Path="/App1" would restrict the availability of the cookie to App1. You could not retrieve it in App2.
You can also scope a cookie by using a domain. For example: Response.Cookies("domain").Domain = "sales.usa.com" would limit the cookie availability to that domain or any sub-domains but not other lateral domains.
For more information on the scope topic, see Microsoft's documentation.
This article has provided specific instructions on using cookies in our ASP.NET applications. We have discussed the major issues we should be thinking about when using them. I hope this information has been useful to you. If you have any comments, suggestions or other ideas, you can email me at RogerMcCook@usermail.com.
Roger D. McCook
McCook Software, Inc.