The Hypertext Transfer Protocol (HTTP) is a stateless protocol. HTTP itself does not provide a Web server with any means of detecting whether two requests originate from the same browser. From the point of view of a Web server, every request for a page is from a new user. This fact is inconvenient for someone developing a Web site. If you want to associate a shopping cart with a user as he or she navigates from page to page, or you need to enable a user to complete forms that span multiple pages, you need to perform some extra work.
Cookies are little pieces of information that a server stores on a browser. According to the original Netscape specification, a cookie cannot contain more than 4KB (the size refers to the combined size of the cookie's name and value).
Certain cookies are temporary; others are persistent. The temporary cookies, called session cookies , exist only in the browser's memory. When the browser is shut down, any session cookies added to the browser are lost.
Persistent cookies , on the other hand, can survive for months or even years . Browsers that support cookies maintain one or more special files. These files, called cookie files on Windows machines and magic cookie files on the Macintosh, store data from Web sites.
Several Web sites have valuable information on cookies. To view the original Netscape specification for cookies, see this site:
To view the W3C's Reference specification on cookies, visit this site:
Finally, for general information on cookies, go to the following:
How Cookies Work
Cookies are passed back and forth between a browser and server through HTTP headers. The server first creates a cookie by using the Set-Cookie header in a response. Subsequent requests from the browser return this cookie in the Cookie header.
Suppose that you want to create a cookie named UserName that contains the name of a visitor to your Web site. To create this cookie, the server would send a header like this:
Set-Cookie: UserName=Bill+Gates; path=/; domain=superexpert.com; expires=Tuesday, 01-Jan-05 00:00:01 GMT
This header instructs the browser to add an entry to its cookie file. The browser adds the cookie named UserName with the value Bill Gates . Notice that the value of the cookie is URL-encoded.
Furthermore, the header informs the browser that this cookie should be returned to the server regardless of the path used in the request. If the path attribute were set to another value such as /private , the cookie would be returned only in requests to this path.
The domain attribute further restricts where the cookie can be sent by the browser. In this example, the cookie can be sent only to the superexpert.com Web site. The cookie will never be sent to www.yahoo.com or any other Web site on the Internet.
Finally, the expires attribute specifies when the cookie should expire. The header in the example tells the browser to store the cookie until the first second of January 1, 2005. Actually, the cookie will probably expire much earlier than that. When a cookie file becomes too large, the browser automatically starts removing cookies.
After the server creates a cookie, the browser returns the cookie in every request it makes to the Web site. The browser sends the cookie in a header that looks like this:
Cookie: Username: Bill+Gates
Creating and Reading Session Cookies
You can create and read session cookies by using the Cookies property of the Response object and Request class. The Cookies property represents a collection of cookies (an instance of the HttpCookieCollection class).
The following sample statements create a new session cookie named myCookie :
Dim objCookie As New HttpCookie( "myCookie", "Hello!" ) Response.Cookies.Add( objCookie )
The first statement creates an individual cookie named myCookie with the value "Hello!" . The second statement adds the new cookie to the Response object's cookie collection.
The preceding statements create a session cookie. The cookie is added to the browser's memory but not recorded to a file. When the user shuts down the browser, the cookie is wiped from memory.
To read an existing cookie, you access the cookies collection of the Request object. For example, the following statement displays the value of a cookie named myCookie :
Response.Write( Request.Cookies( "myCookie" ).Value )
The Value property returns the value of the cookie as a string.
A cookie can contain only a string value. If you want to store an integer value in a cookie, such as a user ID, you need to convert the value to a string.
You can display all the cookies sent by a browser by iterating through the Request object's cookies collection. Here's how you would display them:
Dim strKey As String For each strKey in Request.Cookies Response.Write( "<li>" & strKey & "=" & _ Request.Cookies( strKey ).Value ) Next
This For...Next loop iterates through all the items in the Request object's cookies collection. The name value of each cookie is displayed in a bulleted list.
The page in Listing 16.1 illustrates how you can add and read a cookie within an ASP.NET page (see Figure 16.1).
Listing 16.1 CreateCookie.aspx
<Script Runat="Server"> Sub Button_Click( s As Object, e As EventArgs ) Dim objCookie As HttpCookie objCookie = New HttpCookie( txtCookieName.Text, txtCookieValue.Text ) Response.Cookies.Add( objCookie ) End Sub Sub Page_PreRender( s As Object, e As EventArgs ) Dim strKey As String For each strKey in Request.Cookies lblCookies.Text &= "<li>" & strKey & "=" & _ Request.Cookies( strKey ).Value Next End Sub </Script> <html> <head><title>CreateCookie.aspx</title></head> <body> <form Runat="Server"> <b>Cookie Name:</b> <br> <asp:TextBox ID="txtCookieName" Runat="Server" /> <p> <b>Cookie Value:</b> <br> <asp:TextBox ID="txtCookieValue" Runat="Server" /> <p> <asp:Button Text="Add Cookie!" OnClick="Button_Click" Runat="Server" /> <h2>Existing Cookies:</h2> <asp:Label ID="lblCookies" EnableViewState="False" Runat="Server" /> </form> </body> </html>
The C# version of this code can be found on the CD-ROM.
Figure 16.1. Creating browser cookies.
The page in Listing 16.1 displays a form with two TextBox controls. You can enter the name and value of a new cookie into the TextBox controls and create a new cookie.
The new cookie is added with the Button_Click subroutine. This subroutine simply grabs the values from the two TextBox controls and adds the new cookie to the cookies collection of the Response object.
Finally, the page displays all existing cookies in the Page_PreRender subroutine.
In Listing 16.1, you display the cookies in the Page_PreRender subroutine instead of the Page_Load subroutine so that you can display any cookies added with the Button_Click subroutine. The Page_Load subroutine is executed before event-handling subroutines, such as Button_Click . The Page_PreRender subroutine isn't executed, in contrast, until the page is about to be rendered.
Creating and Reading Persistent Cookies
A persistent cookie is similar to a session cookie, except for the fact that a persistent cookie has a definite expiration date. When a browser requests a page that creates a persistent cookie, the browser saves the cookie to the hard drive. You can create a persistent cookie that lasts months or even years on a user's computer.
You have no guarantee that a persistent cookie will remain on a user's computer for the period of time that you specify. A browser places a limit on the total number of cookies that it will store from all Web sites. After that limit is reached, the browser starts automatically deleting cookies. Users can also choose to delete cookies from the computer before they expire.
Persistent cookies are often used to store information such as usernames or user IDs. That way, the server can identify the same user when he or she returns to the Web site in the future.
Persistent cookies are stored in plain text files on a user's computer. You therefore should never store sensitive information, such as passwords or credit card numbers , in a persistent cookie.
You can create a persistent cookie that lasts until December 25, 2005, as follows :
Dim objCookie As New HttpCookie( "myPersistentCookie", "Hello!" ) objCookie.Expires = #12/25/2005# Response.Cookies.Add( objCookie )
Notice that the only difference between a session and persistent cookie is the addition of expiration information. If you want to add a persistent cookie that will last the maximum amount of time, you can use the following statements:
Dim objCookie As New HttpCookie( "myPersistentCookie", "Hello!" ) objCookie.Expires = DateTime.MaxValue Response.Cookies.Add( objCookie )
After you create a persistent cookie, you can read it in the same way as you would a session cookie. You can access a persistent cookie through the Cookies property of the Request object like this:
Response.Write( Request.Cookies( "myPersistentCookie" ).Value )
This statement displays the value of a persistent cookie named myPersistentCookie .
Setting Cookie Properties
You can set any of the following properties of a cookie:
The Domain property enables you to specify a particular domain for a cookie so that the cookie is sent only with requests to that domain. You cannot specify a domain that is different from the domain used by your Web server. For example, if your Web site is www.myCompany.com , you cannot assign the value www.Yahoo.com to the Domain property.
However, you can specify different hostnames for the domain, such as products.myCompany.com , sales.myCompany.com , or www.myCompany.com .
You should never change the Path property from its default value. By default, a browser sends a cookie for a domain with every request for a page at a Web site. If you specify a subdirectory by using the Path property, however, the cookie should be sent only with requests for pages in the subdirectory.
Unfortunately, there is a known problem with the way the Netscape browser handles the Path property. The Netscape browser uses case-sensitive paths. Therefore, a request for a page at /myDirectory/myPage.aspx is treated differently than a request for a page at /MYDIRECTORY/mypage.aspx .
Finally, notice that two of the properties enable you to work with cookie dictionaries. A cookie dictionary is a single cookie that stores multiple key and value pairs. The HasKeys property enables you to detect whether a cookie is a cookie dictionary. The Values property enables you to read the keys and values from a cookie dictionary.
The following sample statements create a new cookie dictionary named Preferences :
Dim objCookie As HttpCookie objCookie = New HttpCookie( "Preferences" ) objCookie.Values( "color" ) = "Red" objCookie.Values( "fontface" ) = "Arial" objCookie.Values( "fontsize" ) = "4" Response.Cookies.Add( objCookie )
These statements create a new cookie dictionary that contains three name and value pairs: color , fontface , and fontsize . Since no expiration information is set, the cookie is created as a session cookie.
You can detect whether any cookie is a cookie dictionary by using the HasKeys property. For example, the following statements use the HasKeys property to detect whether a cookie is a cookie dictionary and display each of its entries:
If objCookie.HasKeys Then Dim strItem As String For Each strItem in objCookie.Values Response.Write( "<li>" & strItem & _ "=" & objCookie.Values( strItem ) ) Next End If
Examining Limitations of Cookies
Cookies are fine for storing a small amount of string information on a user's browser. However, they have some significant limitations. First, an individual cookie can contain a very limited amount of information (no more than 4KB). This means, for example, that you should not attempt to store a user's shopping cart directly in a cookie.
Another limitation is that you cannot store anything but a string in a cookie. This means that you cannot store such complex objects as HashTables or DataSets in a cookie.
The ASP.NET framework includes built-in support for using cookies in this way. You can automatically track a user with a cookie and associate resources on the server with the user by taking advantage of session state. In the next section of this chapter, "Using Session State," you learn how to take advantage of session state.
Another significant limitation of cookies is that they are browser-dependent. For various reasons, cookies do not work with all browsers. In some cases, users have disabled cookies on their browsers in response to security or privacy worries. In other cases, a user's cookie file has become corrupted. Finally, cookies do not always work well with company proxy servers.
The general warning is that you are taking a risk whenever you rely on cookies. Your Web pages will not work for a certain percentage of users. Whenever possible, you should try to avoid using cookies for crucial functions.
In the section "Using Cookieless Sessions" later in this chapter, you learn how to take advantage of a method of retaining state without cookies. The ASP.NET framework includes a tricky method of tracking users as they move from page to page that does not rely on cookies.