ptg 1274 CHAPTER 28 Maintaining Application State <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <title>Delete Cookie</title> </head> <body> <form id=”form1” runat=”server”> <div> <asp:Label id=”lblCookieName” Text=”Cookie Name:” AssociatedControlID=”txtCookieName” Runat=”server” /> <asp:TextBox id=”txtCookieName” Runat=”server” /> <asp:Button id=”btnDelete” Text=”Delete Cookie” OnClick=”btnDelete_Click” Runat=”server” /> </div> </form> </body> </html> The particular date that you specify when deleting a cookie doesn’t matter as long as it is in the past. In Listing 28.5, the expiration date is set to one day ago. The page in Listing 28.6 deletes all cookies sent from the browser to the current domain (and path). LISTING 28.6 DeleteAllCookies.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> void Page_Load() { string[] cookies = Request.Cookies.AllKeys; foreach (string cookie in cookies) From the Library of Wow! eBook ptg 1275 Using Browser Cookies { BulletedList1.Items.Add(“Deleting “ + cookie); Response.Cookies[cookie].Expires = DateTime.Now.AddDays(-1); } } </script> <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <title>Delete All Cookies</title> </head> <body> <form id=”form1” runat=”server”> <div> <h1>Delete All Cookies</h1> <asp:BulletedList id=”BulletedList1” EnableViewState=”false” Runat=”server” /> </div> </form> </body> </html> The page in Listing 28.6 loops through all the cookie names from the Request.Cookies collection and deletes each cookie. Working with Multivalued Cookies According to the cookie specifications, browsers should not store more than 20 cookies from a single domain. You can work around this limitation by creating multivalued cookies. A multivalued cookie is a single cookie that contains subkeys. You can create as many subkeys as you need. For example, the page in Listing 28.7 creates a multivalued cookie named preferences. The preferences cookie stores a first name, last name, and favorite color (see Figure 28.3). 28 From the Library of Wow! eBook ptg 1276 CHAPTER 28 Maintaining Application State LISTING 28.7 SetCookieValues.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> void btnSubmit_Click(Object s, EventArgs e) { Response.Cookies[“preferences”][“firstName”] = txtFirstName.Text; Response.Cookies[“preferences”][“lastName”] = txtLastName.Text; Response.Cookies[“preferences”][“favoriteColor”] = txtFavoriteColor.Text; Response.Cookies[“preferences”].Expires = DateTime.MaxValue; } </script> <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <title>Set Cookie Values</title> </head> <body> <form id=”form1” runat=”server”> <div> FIGURE 28.3 Creating a multivalued cookie. From the Library of Wow! eBook ptg 1277 Using Browser Cookies <asp:Label id=”lblFirstName” Text=”First Name:” AssociatedControlID=”txtFirstName” Runat=”server” /> <br /> <asp:TextBox id=”txtFirstName” Runat=”server” /> <br /><br /> <asp:Label id=”lblLastName” Text=”Last Name:” AssociatedControlID=”txtFirstName” Runat=”server” /> <br /> <asp:TextBox id=”txtLastName” Runat=”server” /> <br /><br /> <asp:Label id=”lblFavoriteColor” Text=”Favorite Color:” AssociatedControlID=”txtFavoriteColor” Runat=”server” /> <br /> <asp:TextBox id=”txtFavoriteColor” Runat=”server” /> <br /><br /> <asp:Button id=”btnSubmit” Text=”Submit” OnClick=”btnSubmit_Click” Runat=”server” /> </div> </form> </body> </html> 28 From the Library of Wow! eBook ptg 1278 CHAPTER 28 Maintaining Application State When you submit the page in Listing 28.7, the following HTTP header is sent to the browser: Set-Cookie: preferences=firstName=Steve&lastName=Walther&favoriteColor=green; expires=Fri, 31-Dec-9999 23:59:59 GMT; path=/ The page in Listing 28.8 reads the values from the preferences cookie. LISTING 28.8 GetCookieValues.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> void Page_Load() { if (Request.Cookies[“preferences”] != null) { lblFirstName.Text = Request.Cookies[“preferences”][“firstName”]; lblLastName.Text = Request.Cookies[“preferences”][“lastName”]; lblFavoriteColor.Text = Request.Cookies[“preferences”][“favoriteColor”]; } } </script> <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <title>Get Cookie Values</title> </head> <body> <form id=”form1” runat=”server”> <div> First Name: <asp:Label id=”lblFirstName” Runat=”server” /> <br /> Last Name: <asp:Label id=”lblLastName” Runat=”server” /> <br /> Favorite Color: <asp:Label id=”lblFavoriteColor” Runat=”server” /> From the Library of Wow! eBook ptg 1279 Using Session State </div> </form> </body> </html> You can use the HttpCookie.HasKeys property to detect whether a cookie is a normal cookie or a multivalued cookie. Using Session State You can’t use a cookie to store a shopping cart. A cookie is just too small and too simple. To enable you to work around the limitations of cookies, ASP.NET Framework supports a feature called Session state. Like cookies, items stored in Session state are scoped to a particular user. You can use Session state to store user preferences or other user-specific data across multiple page requests. Unlike cookies, Session state has no size limitations. If you had a compelling need, you could store gigabytes of data in Session state. Furthermore, unlike cookies, Session state can represent more complex objects than simple strings of text. You can store any object in Session state. For example, you can store a DataSet or a custom shopping cart object in Session state. You add items to Session state by using the Session object. For example, the page in Listing 28.9 adds a new item named message to Session state that has the value Hello World!. LISTING 28.9 SessionSet.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> void Page_Load() { Session[“message”] = “Hello World!”; } </script> <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <title>Session Set</title> </head> <body> <form id=”form1” runat=”server”> 28 From the Library of Wow! eBook ptg 1280 CHAPTER 28 Maintaining Application State <div> <h1>Session item added!</h1> </div> </form> </body> </html> In the Page_Load() event handler in Listing 28.9, a new item is added to the Session object. You can use the Session object just as you would use a Hashtable collection. The page in Listing 28.10 illustrates how you can retrieve the value of an item that you have stored in Session state. LISTING 28.10 SessionGet.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> void Page_Load() { lblMessage.Text = Session[“message”].ToString(); } </script> <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <title>Session Get</title> </head> <body> <form id=”form1” runat=”server”> <div> <asp:Label id=”lblMessage” Runat=”server” /> </div> </form> </body> </html> From the Library of Wow! eBook ptg 1281 Using Session State When you use Session state, a session cookie named ASP.NET_SessionId is added to your browser automatically. This cookie contains a unique identifier. It is used to track you as you move from page to page. When you add items to the Session object, the items are stored on the web server and not the web browser. The ASP.NET_SessionId cookie associates the correct data with the correct user. By default, if cookies are disabled, Session state does not work. You don’t receive an error, but items that you add to Session state aren’t available when you attempt to retrieve them in later page requests. (You learn how to enable cookieless Session state later in this section.) WARNING Be careful not to abuse Session state by overusing it. A separate copy of each item added to Session state is created for each user who requests the page. If you place a DataSet with 400 records into Session state in a page, and 500 users request the page, you have 500 copies of that DataSet in memory. By default, ASP.NET Framework assumes that a user has left the website when the user has not requested a page for more than 20 minutes. At that point, any data stored in Session state for the user is discarded. Storing Database Data in Session State You can use Session state to create a user-relative cache. For example, you can load data for a user and enable the user to sort or filter the data. The page in Listing 28.11 loads a DataView into Session state. The user can sort the contents of the DataView by using a GridView control (see Figure 28.4). 28 From the Library of Wow! eBook ptg 1282 CHAPTER 28 Maintaining Application State LISTING 28.11 SessionDataView.aspx <%@ Page Language=”C#” %> <%@ Import Namespace=”System.Data” %> <%@ Import Namespace=”System.Data.SqlClient” %> <%@ Import Namespace=”System.Web.Configuration” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> DataView dvMovies; /// <summary> /// Load the Movies /// </summary> void Page_Load() { dvMovies = (DataView)Session[“Movies”]; if (dvMovies == null) { string conString = WebConfigurationManager.ConnectionStrings[“Movies”].ConnectionString; SqlDataAdapter dad = FIGURE 28.4 Sorting a DataView stored in Session state. From the Library of Wow! eBook ptg 1283 Using Session State new SqlDataAdapter(“SELECT Id,Title,Director FROM Movies”, conString); DataTable dtblMovies = new DataTable(); dad.Fill(dtblMovies); dvMovies = new DataView(dtblMovies); Session[“Movies”] = dvMovies; } } /// <summary> /// Sort the Movies /// </summary> protected void grdMovies_Sorting(object sender, GridViewSortEventArgs e) { dvMovies.Sort = e.SortExpression; } /// <summary> /// Render the Movies /// </summary> void Page_PreRender() { grdMovies.DataSource = dvMovies; grdMovies.DataBind(); } </script> <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <title>Session DataView</title> </head> <body> <form id=”form1” runat=”server”> <div> <asp:GridView id=”grdMovies” AllowSorting=”true” EnableViewState=”false” OnSorting=”grdMovies_Sorting” Runat=”server” /> <br /> <asp:LinkButton id=”lnkReload” Text=”Reload Page” Runat=”server” /> </div> 28 From the Library of Wow! eBook . eBook ptg 1276 CHAPTER 28 Maintaining Application State LISTING 28.7 SetCookieValues.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC -/ /W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>. preferences=firstName=Steve&lastName=Walther&favoriteColor=green; expires=Fri, 31-Dec-9999 23:59:59 GMT; path=/ The page in Listing 28.8 reads the values from the preferences cookie. LISTING 28.8 GetCookieValues.aspx <%@ Page. Figure 28 .4) . 28 From the Library of Wow! eBook ptg 1282 CHAPTER 28 Maintaining Application State LISTING 28.11 SessionDataView.aspx <%@ Page Language=”C#” %> <%@ Import Namespace=”System.Data”