Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Yet, another ViewState viewer

0.00/5 (No votes)
7 Mar 2004 3  
In the following lines, I'll show how to create a very simple viewer that displays the contents of the controls store in view state. It's NOT just a tree holding all the ViewState data as stored in __VIEWSTATE field, but a list of all the controls storing data in ViewState and the saved data.

Sample screenshot

Abstract

In the following lines, I�ll show how to create a very simple viewer that displays the content of the controls store in view state. It�s not just a tree holding all the ViewState data as stored in __VIEWSTATE field, but a list of all the controls storing data in ViewState and the data saved in view state by each control. This will therefore work to reveal how ASP.NET arranges data regarding the controls saved in ViewState, and the data each one of those controls preserve.

The Problem

As a part of the PostBack mechanism introduced in ASP.NET, Microsoft created the ViewState method to reduce page creation time at PostBack. The idea behind ViweState is simple: while page is created for the first time, some of the controls data are fetched from the data sources (such as the Database). When the user starts a server event from the client, all the page controls are recreated to process incoming server side events. To prevent access of data sources controls data, which wasn�t sent using HTML Form, it can be serialized into a hidden text field (__VIEWSTATE) and sent to the client as a part of the HTML form. When a server side event is required, the hidden __VIEWSTATE field that holds the control serialized data is sent over to the server. ASP.NET can use __VIEWSTATE field preserved data to recreate controls instead of accessing data storage to get controls data. In addition to control usage of ViewState, ASP.NET enables programmers to add their own data into ViewState, so they can preserve the data over page calls.

You may ask then which controls use ViewState and what exactly they preserve in ViewState? I decided to take the challenge and to create a viewer displaying all the controls that preserve data in view state and the data that those controls preserve.

There are four main methods involved in handling ViewState in the Page level. SavePageStateToPersistenceMedium and LoadPageStateFromPersistenceMedium methods are responsible for saving/loading ViewState to/from persistence medium (default persistence medium is a hidden field). LoadViewState and SaveViewState methods, actually handle the data which eventually loads/saves onto the persistence media. As part of ViewState handling LoadViewStateRecursive and SaveViewStateRecursive methods of the Control class are called from LoadViewState and SaveViewState methods to handle page controls ViewState recursively.

If you will override page SavePageStateToPersistenceMedium method and inspect the only parameter that passes to SavePageStateToPersistenceMedium, you will see that this parameter holds a tree of objects. Going down the tree you will see Triplets, Pairs and Arrays. All of those container classes are used altogether to store Page and controls ViewState. Triplets are classes consisting of three Objects and Pairs, as the name would suggest, two. Every object of those classes can be another Triplet, Pair, ArrayList, Array and every one of them may contain other objects and so on. Triplet, Pair, ArrayList, Array may also contain strings and primitive types. ASP.NET uses LosFormatter class to serialize ViewState tree into a text sent to the client in a hidden input (__VIEWSTATE).

A quick search in Google ends up with viewers that show only tree view of all Triplet, Pair, ArrayList, Array and primitive types. That's nice, but how can I identify the controls that stored the data and what exactly did they store in those endless Triplet, Pair, ArrayList tree. Specific information about which controls hold data inside ViewState and controls data must be somewhere inside ViewState. That is to say, since ASP.NET knows what ViewState data it needs to send for every control, I should start looking for that data in the ViewState tree.

How ASP.NET saves ViewState data

Apparently there is some logic behind that mass and it goes like this:

0 .Triplet

1 .First(string) - Page hash value

2 .Second(Triplet)

3 .First(Pair)

4 .First(ArrayList) - keys

5 .Second(ArrayList)- values

6 .Third(ArrayList)

7 [X](Triplet)

8 .Second(ArrayList) � array that holds the control Position in Form controls collection.

9 .Third(ArrayList) - array that holds the ViewState for every control from the upper array.

Line 1: it all starts with a triplet (line 0). The first element of the first Triplet holds a string that is a hash key of the control hierarchy of the page which stores ViewState data. The hash key value is passed through view state even if all Page controls' EnableViewstae properties are set to false.

Line 3: if that entry holds a Pair, it means that the user asked to save data in the view state. If the user didn�t save any values to ViewState, this object sets to null.

Line 4: if Line 3 holds Pair, this line is the first Pair object which is ArrayList of all the user Viewstate keys.

Line 5: if Line 3 holds Pair, this line is the second Pair object which is ArrayList of all the user Viewstate values.

Line 6-7: The third object of the second Triplet holds data about which control preserves data in ViewState and the data it preserves. The third object is actually an ArrayList of Triplet objects that holds controls and data. Every entry in the third triplet object (ArrayList) is another Triplet object. That inner triplet holds the interesting data in the second and third objects.

Line 8: The second object in the above inner Triplet is an Arraylist. Every entry in that array holds a value that is the position of control in the controls collection of the HtmlForm object (the Form tag).

Line 9: Points to the third element of the inner Triplet, that is an Arraylist as well. Every entry in that array corresponds to the controls position array and actually holds data that is preserved by the control. That entry in array can be a single value or another complicated sub tree of Triplet, Pairs and ArrayLists.

That�s for the logic of representing a control that preserves data and its data in the ViewState tree. Before we take a look at how to use this logic to display a page ViewState by controls, there are also other conclusions that I gathered regarding controls data structure. Those rules aren�t as firm as the controls logic. What I mean is that controls data rules are usually created but you can�t anticipate a scenario that control vendors might take to preserve data in ViewState.

  1. If Pairs� two objects hold ArrayList they usually represent key / value relationship between the ArrayLists, where usually the first array holds the keys and the second array holds the values.
  2. If Triplets� first object is primitive value while the second and third array holds ArrayList then the Triplet also holds ArrayLists with Key / Value relationship. Usually the first object (primitive value) holds counter of the elements in the ListArrays. As describe above, second and third ArrayLists hold Key / Value data.
  3. There are scenarios where a Triplet holds ArrayList in the second and third objects and the first object is set to null. Those arrays hold Key / Value Data.
  4. If Triplet's first object is primitive type it usually holds data about the number of elements in the second and third objects.

Creating ViewState Viewer

I have implemented my simple viewer inside a separate class (ViewStateViewer) so you could activate it from every page. All you need is simply to call the ViewStateViewer's single public method (GetPageControlsViewState). Using HtmlGenericControl, GetPageControlsViewState will render tree with page, user defined and controls viewstate. Eventually it will look like the image at the top of the article.

The viewer class contains several private methods that are responsible for parsing the tree object recursively and displaying the data as tree; indeed they are pretty easy to follow. The interesting part goes into GetPageControlsViewState method, which holds the logic of getting out from the ViewState data preserved by page, user and controls.

public void GetPageControlsViewState()

{

Create a new HtmlGenericControl for holding the tree data that will be rendering on the page.

System.Web.UI.HtmlControls.HtmlGenericControl VSHtml = new
 System.Web.UI.HtmlControls.HtmlGenericControl();

Check if current request holds PostBack data by checking the hidden field __VIEWSTATE in request Form collection. I use HttpContext.Current.Handler for getting Page object to make this code unbound to any Page.

if(((Page)HttpContext.Current.Handler).Request.Form["__VIEWSTATE"] != null)

{

Get the string that holds the serialized data of ViewState and de-serialize it into an object.

string vsInput = ((Page)HttpContext.Current.Handler).Request.Form
    ["__VIEWSTATE"].Replace("\n", "").Replace("\r", "");
object vsObject = new LosFormatter().Deserialize(vsInput);

Getting the page ViewState is pretty easy. It�s always in the first element of the first Triplet.

VSHtml.InnerHtml = "<b>Page Data : </b><br>" + 
ParseViewState(((Triplet)vsObject).First,1);

Check if the user added custom ViewState values by testing if the second object is a Pair object type. If so, then get the keys and values arrays from the Pair object and loop throughout those arrays to get the key / value pairs and display them.

Triplet Second = (Triplet)((Triplet)vsObject).Second; 
if (Second.First is System.Web.UI.Pair)
{
   System.Web.UI.Pair oPair = (System.Web.UI.Pair)Second.First;
   System.Collections.ArrayList oKeys = 
      (System.Collections.ArrayList)oPair.First; 
   System.Collections.ArrayList oVals = 
      (System.Collections.ArrayList)oPair.Second;
   VSHtml.InnerHtml += "<br><b> User ViewState : </b><BR>";
   for(int i = 0; i<oKeys.Count; i++)
   {
      VSHtml.InnerHtml += "\t Key=" + oKeys[i].ToString () + 
             " Value=" + oVals[i].ToString () + "<br>";
   }
}

Get the third object and loop through the ArrayList items.

ArrayList oArrObjectsAndData = (ArrayList)Second.Third;
for (int iObjAndData=0;iObjAndData<oArrObjectsAndData.Count;iObjAndData++)
{

Get Triplet object from ArrayList and then cast the second (holding objects representation) and the third (ViewState data) objects to ArrayList.

Triplet oTripControls = (Triplet)oArrObjectsAndData[iObjAndData];

ArrayList oArrObjects = (ArrayList)oTripControls.Second;

ArrayList oArrData = (ArrayList)oTripControls.Third;

Loop through the objects ArrayList. For each object:

  1. Get its ID from HtmlForm controls by using control position in the Controls collection;
  2. Get ViewState data of the control from the oArrData ArrayList and parse it.
   for(int iCont =0; iCont < oArrObjects.Count; iCont++) 
   {
      // get the control ID

      string ContID = GetForm().Controls[(int)oArrObjects[iCont]].ID;
      // Get the control ViewState.

      Triplet oTrip = (Triplet)oArrData[iCont];
      VSHtml.InnerHtml += "<br><b>" + ContID + " : </b><BR>" +
                         ParseViewState(oTrip ,5);
   }
}

Set HtmlGenericControl visibility and add it to the parse form collection.

VSHtml.Visible = true;

GetForm().Controls.Add (VSHtml); 

}

}

If you look in the results, you can see that every control has its logic for storing ViewState. ListBox holds Triplet with two arrays. One holds the display values and the other holds their corresponding values. Grid saves several arrays that hold general information about itself (number of rows, page etc.) and values and value types for each cell. With a small effort, you can create custom viewer for each server control, check for the type of the control that preserves data and use its custom viewer.

Using this code, you can easily see which objects preserve data in the ViewState and what data the objects are preserving. If you take it one step ahead, you can develop custom viewers to display server control view state in a more readable manner.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here