Deal With View State Issues

Learn to face and solve your view state troubles.





Deal With View State Issues

Learn to face and solve your view state troubles.


By Dino Esposito


The view state is the heart of the ASP.NET built-in system that enables server controls to persist some properties across page roundtrips. Implemented as a dictionary of name/value pairs, the view state of all controls that form a page is first flushed to a single hierarchical structure and then serialized to an array of bytes. At the end of the process, the view state is stuffed into a hidden field and carried back and forth to the client. The view state is always managed on the server, courtesy of the HTTP pipeline that makes a Web request become plain HTML text.


The view state is a powerful but potentially delicate feature of ASP.NET. It is powerful because it enables stateful programming over a stateless protocol such as HTTP. The view state is the container that pages use to preserve their state. When the page posts back, the page framework deserializes the view state - if the view state is present - and sets up a runtime environment that recreates the same situation of the time in which the page was initially sent to the browser. Each involved control saves its critical state into the view state and the page framework restores it when processing the page back. The state information, properly encoded, goes to the client, but is not used by the browser or the client-side environment. The view state represents the context of the call as prepared and served by the ASP.NET page framework. Page authors can control, both in quantity and quality, the data stored in the view state and an effective management of the view state can mark the difference between a good and a poor application design. If, for any reasons, the view state is altered along the way an error occurs. Furthermore, a too large view state can easily slow down the page.


Watch Your View State Types

Bear in mind that not all data types that an ASP.NET application is enabled to use can be saved to the view state. For example, a data type that is not serializable cannot be persisted in the view state. However, non-serializable types for which you define a type converter class can be stored in the view state. A type converter is a class that performs two-way conversion between the value of a custom type and plain text. The type converter class has the capability of rendering the contents of a custom type as text to the user. In addition, the type converter can rebuild a valid instance of that type based on a properly formatted string of text. In summary, any data types you plan to store in the view state must either be serializable or supply a type converter class. Notice, though, that types that are serializable but lack a type converter are slower to serialize and generate a much larger output than those based on a type converter.


For performance reasons, and to generate a more compact array of bytes, you should ensure that the view state contains only simple types or types that provide a type converter. (Basically, the type converter transforms a "complex" type in a simple, text-based representation.) Note that a TypeConverter for a type is implemented outside the type itself and is associated with it by applying a TypeConverterAttribute attribute:



public class YourClass {




In the previous code snippet the converter class is YourClassConverter bound to the YourClass type using the TypeConverter attribute. On a side note, consider that the type converter object has a double use. Not just the ASP.NET framework employs it at runtime during the view state serialization, but also at design time to provide properties of that type with an appropriate representation in the property grid.


What is the main reason for limiting the use of certain types - both user-defined classes and the majority of the classes in the .NET Framework - when it comes to storing data to the view state? The magic word is optimization.


The LOS Formatter

Both to minimize the size of the hidden field and to generate the output faster, the ASP.NET page framework serializes the view state using an internal serialization format that is optimized for primitive types, and for String, ArrayList, and HashTable types. This format is known as the Limited Object Serialization (LOS).


LOS is designed for obtaining the maximum compression of a limited number of data types. Classes that implement the LOS algorithm are not completely public and fully documented because (as of ASP.NET 1.1) LOS is considered a feature internal to the ASP.NET framework. LOS is not designed to be a general-purpose serialization mechanism, but simply a format optimized for persisting some data across Web requests. The schema of the LOS format is subject to change as future versions of ASP.NET see the light.


The idea behind the LOS format is based on a few known facts. The most common data types that people need to persist are strings, arrays, and hashtables. Furthermore, hashtables and arrays are likely to contain null or repeated entries. Finally, there are a set of common types (Int32, Boolean, Color, Unit) that would make up almost the whole of the non-string and non-collection data.


For all of these types the LOS formatter is at its best. If you store a different type, the formatter first attempts to find a type converter so that the data is persisted as a string. If no type converter exists, the default binary serialization is used. In terms of raw performance and the space occupation, the binary serialization is significantly worse than the LOS formatter.


Each control, including the Page class, has its own view state. The view state is implemented as an instance of the StateBag class, a dictionary class with a few customized members. The view state of the page is serialized a moment before the page is rendered to HTML. When this happens, the ViewState property of all constituent controls is flushed into an all-encompassing structure, which is then serialized to an array of bytes using the LOS formatter. The view state information is stored using a hashtable indexed by control name in which each entry contains a hashtable of children and data. Next, the array of bytes is Base64 encoded and flushed into a hidden field in the page that goes to the browser. In no case does the view state get encrypted.


Optimizing pages and controls that make an intensive use of the view state is a delicate art. The best two practices for view state fine tuning are summarized in the section "Customize the View State Management" toward the end of this article.


Fend Off View State Corruption

When your application raises a view state error, chances are that the error message has to do with a "presumed" corruption of the stored data. What the ASP.NET framework reports as a corruption is simply the system's inability to restore the posted view state. As mentioned, the view state is stuffed into a hidden field named __VIEWSTATE appended to the page served to the browser. When the page posts back, the hidden field is part of the posted values. The framework looks up for a __VIEWSTATE field and reads its Base64 encoded text. After decoding the text, the page passes it to the LoadViewState method of page constituent controls, giving each a chance to extract any pertinent information.


Before the process starts, though, the ASP.NET framework performs a security check on the view state returned from the client. If the EnableViewStateMac page directive is enabled (yes by default), the view state serializer calculates a hash value on the array of bytes resulting from the LOS serialization. This 20-byte hash value is appended to the array.


When the user works with the page on the client, the view state is there stored in a hidden field, but potentially exposed to any sort of manipulation. Attackers could dissect the view state and insert anything new - from malicious script code to inconsistent values. Particularly at risk are server controls that don't HTML-encode their output, such as DataGrid, DataList, and Label to name just a few.


The appended hash value guarantees that the view state has not been tampered with. Can an attacker modify the hash value too? While this can't be excluded, it is rather a remote possibility. Let's see why. The hash value is calculated using the Secure Hash Algorithm 1 (SHA1) algorithm or any hash or encryption algorithm of choice. The SHA1 algorithm produces a larger hash size than other algorithms such as Message Digest 5 (MD5) and is considered more secure. The hash algorithms don't work on the view state contents alone. The source is enriched by other information such as the validation key, the class name of the page, its source path, plus - in ASP.NET 1.1 only - any custom string that the user places in the ViewStateUserKey property of the Page class. To be able to corrupt the view state, an attacker must know this information too. In particular, the validation key is generated at setup time and stored in the Local Security Authority (LSA) area. This is difficult information for an attacker to crack.


You should note that view state protected with SHA1 or MD5 can be decoded in transit or on the client side and can potentially be viewed in plain text. To avoid this, you might want to opt for a slower approach based on a true encryption algorithm such as the 3 Data Encryption Standard (3DES). Using 3DES you can detect changes in the view state and to also encrypt it while in transit, adding confidentiality to the data. When in this state, even if view state is decoded, it cannot be viewed in plain text.


What's the role of the EnableViewStateMac attribute? If set to true, the hash value (known as the message authentication code) is recalculated and compared to that appended to the view state. If the two don't match, the framework concludes that the view state has been corrupted and throws an exception.


A simple debugging tip is, set the EnableViewStateMac attribute to false and re-run the page. Yours is not a security problem if the error persists. If the page runs just fine, you have reasons to be concerned about security; something happened to modify the page under your user's nose.


Dealing With Long View States

So the view state is packed and persisted as a hidden field. However, the view state of real-world pages can easily reach the remarkable size of 10KB or so. Another frequent reason that may lead to invalid view state exceptions is that the underlying browser is not capable of carrying all those bytes back and forth. As a result, the contents of the view state is truncated. This is particularly likely to happen on pretty simple Web browsers such as WebTVs and PDAs. How do you work around this issue? And just how did the ASP.NET team solve the same issue in ASP.NET mobile controls?


The view state is saved to a hidden field only by default; you can decide to persist it elsewhere. The view state of ASP.NET mobile controls is left on the server stored in Session. The same route can be taken here to support browsers that cannot handle such large hidden fields and resulting requests. In Figure 1 you can see how to proceed overriding a couple of methods. Figure 2 shows the sample page with no view state bundled.


<%@ language="C#" %>



Figure 1. To change the way in which the view state is stored you must simply override the method LoadPageStateFromPersistenceMedium and SavePageStateToPersistenceMedium.


Figure 2. The sample page doesn't show off view state information, although the read-only attribute of the textbox is just a piece of information that normally goes to the view state.


Customize the View State Management

It's common knowledge that the overall size of the view state goes with the number of controls that form the page. Not all controls, though, affect the size of the view state in the same manner. The amount of data that a TextBox control places in the view state pales compared to say, what a DataGrid persists. Each control exposes its own view state through the ViewState property and uses this dictionary to persist critical data across roundtrips. The programmer, though, can exercise some control over the quantity of data that server components store in the view state. This can be accomplished in either of two ways. First, the programmer can disable the view state for all controls in a page or for a specific control. If you're going to implement such a feature, you should double check your code to ensure that no unpleasant side effects sneak into your application. In fact, disabling the view state of a control can certainly improve performance, but can hinder the functionality of the component across roundtrips because of properties that do not retain their last set value.


You can also control the way in which a data type is stored in the view state. This possibility comes in handy especially when you deal with a custom type that otherwise cannot be stored in the view state. The base class Control provides two overridable methods for you to control the view state serialization and deserialization process for the control. The methods are SaveViewState and LoadViewState:


protected virtual object SaveViewState();

protected virtual void LoadViewState(object savedState);


You have to override them in pairs. SaveViewState creates and returns a data structure that contains the information to save. LoadViewState receives the same structure as packed by SaveViewState, extracts the data, and populates the internal members.


Dino Esposito is a trainer and consultant who specializes in ASP.NET, ADO.NET, and XML. Author of Programming Microsoft ASP.NET and Building Web Solutions with ASP.NET and ADO.NET (both from Microsoft Press), Dino is also the cofounder of Write to him at mailto:[email protected].




Hide comments


  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.