WEBSITE

ASP.NET State Management : The View State of a Page (part 3) - Changes in the ASP.NET View State

5/15/2013 1:51:01 AM

4. Changes in the ASP.NET View State

Two important changes occurred to the view-state implementation starting with ASP.NET 2.0. As a result, two major drawbacks have been fixed, or at least greatly mitigated. The size of the view state is significantly reduced as a result of a new serialization format. The contents of the view state have been split into two states: classic view state and control state. Unlike the classic view state, the control state can’t be disabled programmatically and is considered a sort of private view state for a control. This feature is ideal for developers building third-party ASP.NET controls, as it helps them to keep critical persistent properties out of the reach of end page developers.

The Serialization Format

In Figure 2, you see the same page running under ASP.NET 1.x (the bottom window) and ASP.NET 2.0 or ASP.NET 3.5 (the top window). A client-side button retrieves the view-state string and calculates its length. The JavaScript code needed is pretty simple:

<script language="javascript">
    function ShowViewStateSize() {
        var buf = document.forms[0]["__VIEWSTATE"].value;
        alert("View state is " + buf.length + " bytes");
    }
</script>

Figure 2. The overall view state size obtained scriptwise.

As you can see, the size of the view state for the same page is quite different, and significantly smaller, in newer versions of ASP.NET. Let’s see why.

The contents persisted to the view state are ultimately the results of the serialization process applied to an object graph. The object graph results from the hierarchical concatenation of the view state of each individual control participating in the page’s construction. The data going to the view state is accumulated in tuples made of special containers such as Pair and Triplet. Pair and Triplet are extremely simple classes containing two and three members, respectively, of type object. Each object is serialized to the stream according to various rules:

  • Simple types such as strings, dates, bytes, characters, Booleans, and all types of numbers are written as is to a binary stream.

  • Enum types and Color, Type, and Unit dictionary objects are serialized in a way that is specific to the type.

  • All other objects are checked to see whether there’s a type converter object to convert them to a string. If there is, the type converter is used.

  • Objects that lack a type converter are serialized through the binary formatter. If the type is not serializable, an exception is thrown.

  • Pair, Triplet, and ArrayList objects are recursively serialized.

The resulting stream is hashed (or encrypted, based on configuration settings), Base64 encoded, and then persisted to the hidden field. This is more or less what happens already in ASP.NET 1.x. So where’s the difference?

The difference is all in a little detail lying in the folds of type serialization. The type of each member being serialized is identified with a byte—exactly, nonprintable characters in the 1 through 50 range. In ASP.NET 1.x, printable characters—such as <, >, l, s, I, and a few more—were used for the same purpose. This change brings two benefits—a smaller size and a little more speed in deserialization.

Note

The class behind the new serialization format of the ASP.NET 2.0 view state is a new type of formatter object—the ObjectStateFormatter class. Specifically designed in ASP.NET 2.0 to serialize and deserialize object graphs to and from a binary writer, the class is a yet another .NET formatter object, as it also implements the IFormatter interface. In ASP.NET 2.0 and beyond, the ObjectStateFormatter class replaces the LosFormatter class used in ASP.NET 1.x. LosFormatter writes to a text writer. This change is not an optimization per se, but it allows a number of other improvements. For example, it allows indexing of strings and more compact storage, as non-string values (such as numbers and Booleans) are written as binaries and take up much less space.


The Control State

It is not uncommon for a server control to persist information across postbacks. For example, consider what happens to a DataGrid control modified to support autoreverse sorting. When the user clicks to sort by a column, the control compares the current sort expression and the new sort expression. If the two are equivalent, the sort direction is reversed. How does the DataGrid track the current sort direction? If you don’t place the sort direction property in the control’s view state, it will be lost as soon as the control renders to the browser.

This kind of property is not intended to be used for plain configurations such as pager style or background color. It has an impact on how the control works. What if the control is then used in a page that has the view state disabled? In ASP.NET 1.x, the control feature just stops working. Private or protected properties that are to be persisted across two requests should not be placed in the view state. In ASP.NET 1.x, you can use the session state, the ASP.NET cache, or perhaps another, custom hidden, field.

In ASP.NET 2.0 and beyond, the control state is a special data container introduced just to create a sort of protected zone inside the classic view state. It is safer to use the control state than the view state because application-level and page-level settings cannot affect it. If your existing custom control has private or protected properties stored in the view state, you should move all of them to the control state. Anything you store in the control state remains there until it is explicitly removed. Also the control state is sent down to the client and uploaded when the page posts back. The more data you pack into it, the more data is moved back and forth between the browser and the Web server. You should use control state, but you should do so carefully.

Programming the Control State

The implementation of the control state is left to the programmer, which is both good and bad. It is bad because you have to manually implement serialization and deserialization for your control’s state. It is good because you can control exactly how the control works and tweak its code to achieve optimal performance in the context in which you’re using it. The page’s infrastructure takes care of the actual data encoding and serialization. The control state is processed along with the view state information and undergoes the same treatment as for serialization and Base64 encoding. The control state is also persisted within the same view state’s hidden field. The root object serialized to the view state stream is actually a Pair object that contains the control state as the first element and the classic view state as the second member.

There’s no ready-made dictionary object to hold the items that form the control state. You no longer have to park your objects in a fixed container such as the ViewState state bag—you can maintain control-state data in plain private or protected members. Among other things, this means that access to data is faster because it is more direct and is not mediated by a dictionary object. For example, if you need to track the sort direction of a grid, you can do so using the following variable:

private int _sortDirection;

In ASP.NET 1.x, you resort to the following:

private int _sortDirection
{
   get {
      object o = ViewState["SortDirection"];
      if (o == null)  return 0;
      return (int) o;
   }
   set {ViewState["SortDirection"] = value;)
}

To restore control state, the Page class invokes the LoadControlState on all controls that have registered with the page object as controls that require control state. The following pseudocode shows the control’s typical behavior:

private override void LoadControlState(object savedState)
{
    // Make a copy of the saved state.
    // You know what type of object this is because
    // you saved it in the SaveControlState method.
    object[] currentState = (object[]) savedState;
    if (currentState == null)
        return;

    // Initialize any private/protected member you stored
    // in the control state. The values are packed in the same
    // order and format you stored them in the SaveControlState method.
    _myProperty1 = (int) currentState[0];
    _myProperty2 = (string) currentState[1];
    ...
}

The LoadControlState method receives an object identical to the one you created in SaveControlState. As a control developer, you know that type very well and can use this knowledge to extract any information that’s useful for restoring the control state. For example, you might want to use an array of objects in which every slot corresponds to a particular property.

The following pseudocode gives you an idea of the structure of the SaveControlState method:

private override object SaveControlState()
{
    // Declare a properly sized array of objects
    object[] stateToSave = new Object[...];

    // Fill the array with local property values
    stateToSave[0] = _myProperty1;
    stateToSave[1] = _myProperty2;
    ...

    // Return the array
    return stateToSave;
}

You allocate a new data structure (such as a Pair, a Triplet, an array, or a custom type) and fill it with the private properties to persist across postbacks. The method terminates, returning this object to the ASP.NET runtime. The object is then serialized and encoded to a Base64 stream. The class that you use to collect the control state properties must be serializable. 

Other  
 
Top 10
Review : Sigma 24mm f/1.4 DG HSM Art
Review : Canon EF11-24mm f/4L USM
Review : Creative Sound Blaster Roar 2
Review : Philips Fidelio M2L
Review : Alienware 17 - Dell's Alienware laptops
Review Smartwatch : Wellograph
Review : Xiaomi Redmi 2
Extending LINQ to Objects : Writing a Single Element Operator (part 2) - Building the RandomElement Operator
Extending LINQ to Objects : Writing a Single Element Operator (part 1) - Building Our Own Last Operator
3 Tips for Maintaining Your Cell Phone Battery (part 2) - Discharge Smart, Use Smart
REVIEW
- First look: Apple Watch

- 3 Tips for Maintaining Your Cell Phone Battery (part 1)

- 3 Tips for Maintaining Your Cell Phone Battery (part 2)
VIDEO TUTORIAL
- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 1)

- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 2)

- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 3)
Popular Tags
Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Biztalk Exchange Server Microsoft LynC Server Microsoft Dynamic Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Indesign Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe After Effects Adobe Photoshop Adobe Fireworks Adobe Flash Catalyst Corel Painter X CorelDRAW X5 CorelDraw 10 QuarkXPress 8 windows Phone 7 windows Phone 8