Thursday, May 03, 2007

Viewstate-less ASP.NET Pages

Theoretically speaking, the viewstate of an ASP.NET page is a chunk of data that represents the last known good state of the page. Upon page rendering, each server control stores in the viewstate the current value of each tracked property. The viewstate is persisted for each page instance and retrieved when the same page instance posts back. The goal of the viewstate is supporting the ASP.NET runtime when it comes to distinguishing postback requests from first-time requests and recreating the state the page had last time it served markup to the client. Put another way, the viewstate allows the ASP.NET runtime to start processing the page from where it left off last time. We all know that HTTP requests are stateless and, in light of this, we're not surprised to find out that two successive requests for the same page in the same session are completely independent and decoupled. This is clearly a problem for Web applications—an old problem indeed. If the user types in some text and submits its work to the server, it is a reasonable expectation that the same HTML element used to contain the text doesn't lose its contents upon postback. This is exactly what would happen, until some countermeasures are applied. In classic ASP, countermeasures were more of tricks and made large use of code blocks and the Request object. In ASP.NET, the same pattern was engineered in the framework and took the form of the viewstate.

Practically speaking, the viewstate is a hash table that contains a tree of hash tables, one for each control in the page tree. Each control's hash table contains a collection of name/value entries where name equals the name of a control's property and value is the current value of that property. A control doesn't have to persist to the viewstate all of its properties. Only properties explicitly implemented as trackable go to the viewstate. What makes a control property trackable? Its implementation:




public string Text
{
get { (string) return ViewState["Text"]; }
set { ViewState["Text"] = value; }
}

In this way, whenever you assign a value to the Text property, the value is not stored within the current instance of the control but in a global container—the viewstate. When an ASP.NET page is done with rendering, it asks all controls to save their viewstate to the page's viewstate. The page's viewstate is then serialized to a binary stream and then encoded to Base64. The resulting string is attached to the client markup for the page as a hidden field. In this way, when the page posts back the viewstate is automatically uploaded and used to recreate the last known good state for that instance of the page.

The use of the viewstate is controversial among ASP.NET developers. The most common snag is that it takes up too much bandwidth in download and upload. In effect, the viewstate can easily reach 10 or even 20 KB. In general, it takes much more than the actual markup. And it's completely ignored and useless for client browsers.

Can you disable it programmatically for ASP.NET pages? You bet. You can do that on a per-page and/or per-control basis. And what's the final effect?

You simply lose the last-known good state. Which is not necessarily a bad thing. For example, imagine a page with a TextBox control. By default, the TextBox saves at least 10 properties to the viewstate, including Text, ReadOnly, MaxLength and visual properties. What's the property you really update across postbacks? 99 percent of the time, it is the sole Text property. This means that ReadOnly, MaxLength, and all visual properties most of the time retain the value you originally hard-coded in the ASPX page markup. Those values are automatically restored on each request because a new page instance is created. Unless you change some of these properties programmatically, you don't need viewstate for a text box. Nonetheless, thousands of developers do that. What about the Text property? It still works as expected, even with a disabled viewstate.

Why? It's because the value typed by the user is posted back along with the viewstate and used to overwrite the last-known good state. So as far as the Text property is concerned, losing the last-known good state is no big deal.

The viewstate is a key feature of ASP.NET, and it's on by default for all properties of all controls (that support it). Using it only when strictly needed will reduce the size of the page significantly and with the download speed of the page