10.5 View State
In addition to session state and cookie state, ASP.NET introduces the ability to store client-specific state through a mechanism called view state. View state is stored in a hidden field on each ASP.NET page called __VIEWSTATE. Each time a page is posted to itself, the contents of the __VIEWSTATE field are sent as part of the post. The primary use of view state is for controls to retain their state across post-backs, as described in Chapter 2, but it can also be used as a mechanism for storing generic client-specific state between post-backs to the same page.
View state is accessible from any control and is exposed as a StateBag that supports storing any type that is serializable. Because the Page class is derived from the Control base class, you can access the view state directly from within your pages and indirectly through server-side controls. Listing 10-20 shows the ViewState property of the Control class. The view state for a control is loaded just before the Load event firing, and it is flushed just before the Render method being invoked. This means that you can safely access the ViewState in your Load event handler and that you should make sure it has been populated with whatever state you need by the time your Render method is called.
Listing 10-20: ViewState Property Accessor
public class Control : //... { protected virtual StateBag ViewState {get;} //... }
For an example of using view state, let's reimplement our shopping cart example one more time, this time using view state as the container for client-specific state. Because the StateBag class has a default indexer just as the HttpSessionState class does, the code needs to change very little from our original session statebased implementation. The Item class can be used in its original form with serialization support (not the altered form required for cookie state). The most significant change is that view state does not propagate between pages in an application, so to use it, we must aggregate all of the functionality that relies on client-specific state into a single page. In our example, this means that we must implement the CheckOutPage and the ShoppingPage together in one page. Listing 10-21 shows this implementation.
Listing 10-21: ViewState Shopping Page Example
public class PurchasePage : Page { private void Page_Load(object sender, EventArgs e) { ArrayList cart = (ArrayList)ViewState["Cart"]; if (cart == null) { cart = new ArrayList(); ViewState["Cart"] = cart; } // Print out contents of cart with total cost // of all items tallied int totalCost = 0; foreach (Item item in cart) { totalCost += item.Cost; Response.Output.Write("<p>Item: {0}, Cost: ${1}</p>", item.Description, item.Cost); } Response.Write("<hr/>"); Response.Output.Write("<p>Total cost: ${0}</p>", totalCost); } private void AddItem(string desc, int cost) { ArrayList cart = (ArrayList)ViewState["Cart"]; cart.Add(new Item(desc, cost)); _itemsInCart.Text = cart.Count.ToString(); } // remaining code identical to Listing 10-7 }
Notice that in contrast to the cookie state implementation, we were able to save the ArrayList full of Item instances directly to the ViewState state bag. When the page was rendered, it rendered the ArrayList into a compressed, text-encoded field added as the value of the __VIEWSTATE control on the form. On subsequent post-backs to this page, the view state was then reclaimed from the __VIEWSTATE field, and the ArrayList was once again available in the same form. Like cookie state, view state is sent between the client and the server with each request, so it should not be used for transmitting large amounts of data. For relatively small amounts of data posted back to the same page, however, it provides a convenient mechanism for developers to store client-specific state.