Sunday, February 6, 2011

Viewstate

Viewstate is probably one of the most used features of Asp.Net present since its inceptions i.e Asp.Net 1.0. But it is a widely misunderstood feature too. Most consultants whom I have to spoken to have a very jumbled up or mixed concept of ViewState, with most believing that disabling the ViewState will not show up the values typed in the controls by the user.

Therefore I am attempting to throw some light on this topic and for more details please refer to the references stated below.

Viewstate – What is it?
Viewstate represents the state of the page (or rather controls on the page) on the server before the generated output (i.e HTML and Javascript) is sent to the client. Viewstate is stored as a base 64 encoded hidden field on the page.
Also every control has a ViewState property. Surprised! Read the next para ViewState Internals.

Broadly speaking functions of the Viewstate are:
a. Maintain the values per control basis in the StateBag
b. Keep track of the values that have changed in the ViewState/StateBag(more on this dirtying business later)
c. Persist the dirty Viewstate values from each control into the hidden Viewstate form field
d. On postback load the Viewstate value sin to the viewstate/statebag of each control

Now a natural question that springs to the mind is – Well if you have the controls definitions defined in the .aspx file, why do we need to have this state of the controls persisted in a hidden field? Can’t it be build at the server side using the control definitions in the .aspx or .ascx files? Good question, if you thought about it.

Viewstate Internals
Let us try to understand what exactly is a view state. Every control ( as well as page) derives from the Control object which has a Viewstate property which is nothing but a Statebag collection, something like a dictionary object into which you can store data in key, value format.

Now every control uses this Viewstate to store its properties i.e. rather than defining the property in the control as instance variables like Int, String etc; instead every .net control stores its properties as a key-value pair in the Viewstate.

String _text;
Public string Text {
get { return _text;}
set { _text = value;}
}
I.E. instead of the above code, you will mostly find the following code in the control

Public string Text {
get { return (string)ViewState[“Text”];}
set { ViewState[“Text”] = value;}
}

Page Structure
It is important to also understand how does each page is represented in memory. Well, once compiled the page is represented in memory as a tree structure with the ASPC page itself as the root of that tree and all the controls declared at the top level in the ASPX page form the 2nd level of controls, basically 3 controls; a literal control representing all data till the form tag; the form control ; and again a literal control representing all data beneath the form control. Each control which is part of the form control is represented as a child of the form control. And any controls within the parent control are held as their children. In this way the entire page is represented as a tree structure.

ViewState tracking
Now when a page is requested by the client; it is first created on the server as a tree structure. Each control on the page is created as per its definition in the .aspx file and the properties of the controls are persisted in the Viewstate. When the OnInit() function is fired on the page, it fist recursively fires on each of the child control i.e. this method is executed in the BOTTOM UP manner beginning with the child controls and ending with the page. Immediately after the execution of this OnInit function on each control, TRACKING of view state for that control is set ON. What does this mean?

This is where viewstate/statebag differs from a plain dictionary/hashtable object. Once the tracking property of the ViewState is set; any further change to any of the values OR any additions to the StateBag are marked as dirty. Why?

So that at the time of persisting the ViewState on the HTML page as a base64 encoded property, only the key-value pairs (in each control’s viewstate) which are marked as dirty will be persisted Again we may wonder why?

Because properties of the control which can either be simply recreated from the control definition in the .aspx/.ascx file OR the property which is changed prior to OnInit event, can always be recreated from the definition and/or by the common code which runs during the execution of the page.

Now if any property or data of the control in Viewstate is changed after the Init event, it would be marked as dirty and hence would be persisted on the html page and send to client. When the ViewState is received back, in the LoadViewState event which occurs after the OnInit Event, the properties from the form’s ViewState field are applied back to appropriate control’s ViewState/StateBag collection.

So what does this mean? This means that the data applied to each control’s viewstate will be again marked as dirty, and will be persisted back to the page’s HTML in the next cycle.

Why do I need to understand these intricacies of ViewState?
For various reasons; Primarily it helps us to understand when to set or not set control’s property and when will it be persisted in the ViewState:
1. If we apply default value to a control’s property in the Load Event, the control will always show only the default value. And also setting the property in Load event will always mark it as dirty, since it occurs after the OnInit event ( rougly speaking the event cycle is PreInit; Init;InitComplete; LoadViewState; LoadPostBackData;Load,….,PreRender,Render)
Public Class TestControl: WebControl
{
protected override void OnLoad (EventArgs args)
{
if (!this.IsPostback)
this.Text = Session[“TestSessionKey”] as string;
base.OnLoad(args);
}
}

2. So if we wish to apply a default value, it should be done at the stage of property definition:
Public string Text
{
get
{
return this.ViewState[“Text”] == null ?
Session[“SomeSessionKey”] :
this. ViewState[“Text”] as string;
}
set { ViewState[“Text”] = value;}
}
OR
Declare a handler for the OnInit event on the control definition itself and put the intilization code in the control’s OnInit event.
OR
You can put initialization code in the PreInit Event but unlike Init; Load and PreRender, this is not recursive and is called only on the page.
OR
You can create a custom control by inheriting from any of the existing controls as its base control and then put the initializing code in the constructor of the custom control. 

3. For dynamically created controls, they can be added to their parent controls at any event till PreRender (though it is obviously not the best place to add dynamic controls).
So when is Tracking enabled for the ViewState of these controls? The tracking is obviously enabled after the Init event for the control is fired. And for dynamically created controls, ASP.NET plays a “catch-up” with the event sequence in that control ie. OnInit(); OnLoad(); etc (and any controls it may contain). And this catch-up of events starts as soon as the control is added to the control collections of the page’s tree structure.

Conclusion:-
I would like to end the discussion on ViewState with a question. Why do we need to persist or send the ViewState data onto the page? This ise xtra load on the network twice; once will sending to client and then receiving it on server. What if the ViewState was persisted in the session?
A user views only one page at a time and if we assume that at a given time there are about 100-200 active users and each page has on an average ViewState size of 1MB; then the additional load on the server will be only 100-200MB. Will it be better than persisting the ViewState on the page?
Couple of quick points; from version 2.0 even if viewstate is disabled some mandatory details required for the proper working of the control are kept in the ControlState property and presisted to client in the ViewState hidden field.
Also from release of .Net framework ver 4.0, ViewStateMode property is also introduced; using which the ViewState can be disabled for a page but enabled for certain controls in it.

References:
1. TRULY Understanding ViewState - Infinities Loop - http://weblogs.asp.net/infinitiesloop/archive/2006/08/03/Truly-Understanding-Viewstate.aspx
2. ASP.NET Internals: Viewstate and Page Life Cycle - http://www.codeproject.com/KB/aspnet/aspnetviewstatepagecycle.aspx

No comments:

Post a Comment