Yesterday, when I was debugging a problem on an application of ours, the behavior of the application was very illogical – at least, that’s how it seemed. This is what I was doing: If a local variable (in the code-behind class for the page) was non-null, some logic where to be triggered. And this logic did not work correctly. Eventually, I simplified the program (by hardwiring stuff) to the point where it should really work. But, as you probably have figured out, it didn’t…
Then, the answer was revealed to me; a new thought popped into my mind. The ViewState! Yes, most assuredly, this was the cause of the problem. When I set the EnableViewState=false on my control, it started working correctly again. Hallelujah!
So, what is this whole ViewState thing and why was it causing problems in my specific case?
ViewState: The end-user experience
You can say, without exaggerating too much, that ViewState is one of the core elements of ASP.NET. The key idea is this: imagine an .aspx file that looks like this:
<%@ Page Language="C#" AutoEventWireup="true" %>
<script runat="server">
/// <summary>
/// Gets called when the Button1 is clicked.
/// </summary>
/// <param name="sender">the sender of the event</param>
/// <param name="e">the event arguments</param>
protected void Button1_Click(object sender, EventArgs e)
{
Label1.Text = "Button1 has been clicked!";
}
/// <summary>
/// Gets called when the Button2 is clicked.
/// </summary>
/// <param name="sender">the sender of the event</param>
/// <param name="e">the event arguments</param>
protected void Button2_Click(object sender, EventArgs e)
{
Label1.Text += " Button2 has been clicked!";
}
</script>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<p>
<asp:Label runat="server" ID="Label1" />
</p>
<asp:Button runat="server" ID="Button1"
OnClick="Button1_Click"
Text="Button1" />
<asp:Button runat="server" ID="Button2"
OnClick="Button2_Click"
Text="Button2" />
</div>
</form>
</body>
</html>
(Of course, this example is fictionary; I do not recommend that you place your event handlers in the .aspx file but rather in the code-behind.
This page contains two buttons: Button1 and Button2. When rendered, it looks like this:
![]()
Now, if we click on the Button1, it looks like this:
![]()
No rocket-science yet.
The logic for this page can clearly be understood, without knowing how ASP.NET works “under the hood”. The button was clicked, the event was fired, and the event handler set the text of the Label1 control to “Button1 has been clicked!”. All of this happened before the page was actually rendered to the web browser.
But now, let’s click on Button2 and see what we get:
![]()
Hey, that’s weird, isn’t it? In the Button2_Click() event handler, we only added the “Button2 has been clicked” text, but the “Button1 has been clicked” text still remains anyway…?
This is where ASP.NET deviates from “regular” web programming (think: PHP, CGI, JSP…). Now, if you have only ever used ASP.NET (and never any other web-based programming environment), you might feel like this is the most natural thing in the world. It has to work like this, doesn’t it?
Well… no. Not at all, in fact.
ViewState: The background
Traditionally, before the advent of ASP.NET, if you would want the state of an object (such as the content of a <span> tag) to persist across page requests, you would have to invent this yourself (There might be frameworks that can help in doing this). The default would be that all object state would “fall off” the page if the user would e.g. press F5 in the web browser.
Now, what our friends at Microsoft has been doing is trying to bridge the gap between normal applications (i.e. Windows Forms or similar) and web applications a little. The request/response model traditionally used on the web can be a bit unfriendly to a newcomer. The ASP.NET solution to this challenge is called ViewState.
ViewState: What is is
So, what is this ViewState thing now that I’ve been writing about for a while? Simply put, ViewState is a functionality that lets the state of objects persist between different page requests. What you saw above, with the “Button1/2 has been clicked” texts, is a simple example of this persistence. Another simple visual example of the ViewState functionality would be to let the Button1 handler modify the background color of the page. When clicking the Button2, the modified color would still remain.
A couple of simple rules regarding ViewState:
- All object state gets persisted in the ViewState, for public properties (This can be seen as the general rule; there might be exceptions to it).
- ViewState is only preserved for “server controls”; that is, any tags with the runat=”server” attribute set.
- ViewState is enabled by default in ASP.NET. It can be disabled:
- on control-level, by setting EnableViewState=”false”. On HTML-controls, like a regular div with runat=”server”, the attribute is called enableviewstate instead.
- on page-level, by setting the EnableViewState=”false” attribute on the <%@ Page %> tag.
- on application level, like this (in the Web.config):
<system.web> <pages enableViewState="false"/> </system.web>
Technically, the ViewState is sent in a hidden form field called __VIEWSTATE, as a string of base64-encoded text. If you like, try viewing the source of the previously listed sample page, after having clicked the Button1, and you’ll see that it contains some human-unreadable data. This data contains the “Button1 has been clicked!” text.
Now when we have seen some of the “whys” and the “hows” for the ViewState persistence, let’s get into the even more interesting question about the problems that ViewState can cause you. I promised you at the beginning of this blog posting that it can mess up your life; you will soon see how.
ViewState: When it can cause you headaches
As seen above, I have listed some of the advantages of preserving ViewState; it bridges the gap (slightly) between regular (Windows Forms/WPF) applications and the web. It makes the programming models more homogeneous, making it simpler for people who work with them both.
Still, there are also some disadvantages of this technique. One of the disadvantages is that for a large page, the view state can be pretty big, meaning that quite a lot of data will be transferred over the wire on every page hit. Even though this might not be too big a problem, it can still feel meaningless to have this data being transferred when it’s not really needed (for some applications).
Another disadvantage which was the driving reason for writing this blog entry in the first place is that the view state persistence can cause really difficult, hard-to-track bugs. The code sample below illustrates one such scenario:
<%@ Page Language="C#" AutoEventWireup="true" %>
<script runat="server">
// Dummy child class. In my real-world example, the class
// has some custom behavior that justifies its existence.
public class DropDownListCustom: DropDownList
{
}
/// <summary>
/// Gets called right before the page is rendered.
/// </summary>
/// <param name="sender">the sender of the event</param>
/// <param name="eventArgs">the event arguments</param>
protected void Page_PreRender(object sender, EventArgs eventArgs)
{
// Creates a new DropDownListCustom object with some
// items.
DropDownList dropDownList1 = new DropDownListCustom();
dropDownList1.ID = "DropDownList1";
dropDownList1.Items.Add("Item 1");
dropDownList1.Items.Add("Item 2");
dropDownList1.Items.Add("Item 3");
if (IsPostBack)
{
string formValue = Request.Form["DropDownList1"];
// Display the previously selected value + form
// value so we can clearly see if the assignment
// to the SelectedValue has any effect.
Label1.Text = "Was selected: " + dropDownList1.SelectedValue;
Label2.Text = "Will be selected: " + formValue;
dropDownList1.SelectedValue = formValue;
}
div1.Controls.Add(dropDownList1);
}
</script>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div><asp:Label ID="Label1" runat="server" /></div>
<div><asp:Label ID="Label2" runat="server" /></div>
<div runat="server" id="div1"/>
<asp:Button runat="server" ID="Button1" Text="Button1" />
</form>
</body>
</html>
When viewing this page, it looks like this:

When selecting a different item and clicking Button1, this is what you get:
![]()
As you see, the page is not working correctly. We selected Item 2, and it was correctly passed to the page in the Form variables, but somehow, the assignment to the SelectedValue (the highlighted line in the sample code) had no effect whatsoever.
This sample page has some important characteristics that should be pointed out:
- It uses a custom DropDownList-derived class (When you change the “new DropDownListCustom” initialization to “new DropDownList”, the program works as intended, which leads me to believe that there is something special that a child-class of a System.Web.UI.WebControls class needs to do to make ViewState work correctly).
- It uses dynamic control creation. This is from the real-world scenario; what we do is generate the controls depending on some input data. The number of controls generated is dependent on the input data, which means that hardwiring it in the .aspx file is impossible.
- The initialization is only done when performing a postback (not on the initial page load). When thinking about it, this initialization shouldn’t even be necessary; the ViewState + postback handling in ASP.NET “should” be clever enough to set the default value of the DropDownList automatically. That’s how it usually work, isn’t it? But try commenting out the assignment to dropDownList1.SelectedValue and you’ll see that it makes absolutely no difference.
Now, there are two ways to solve this:
- Disable ViewState on the DropDownListCustom control. If the DropDownListCustom control is always (or most of the time) used in scenarios like this, you can create a constructor that sets the default value of the base.EnableViewState property to false (this is what I did). You can always reenable it for those controls that need it.
- Move the div1.Controls.Add to line 24 in the sample (right before the “if (isPostback)”-line). This also makes it work.
The reason why this fails is this: When adding controls dynamically, like we’re doing here, the loading of the persisted ViewState of the control being added takes place at a different stage in the ASP.NET Page Life-cycle than it would normally have taken… This, in combination with some bug/behavior when childclassing the DropDownList causes this behavior.
One lesson learned here for me personally is that maybe ViewState shouldn’t be the default when I work on a new project. As mentioned earlier in the posting, the possibility is there to disable it in the Web.config. I don’t know if you can still re-enable it on individual pages (where it would be needed); if that’s the case, this might the optimal way to go. Then again, ViewState is extremely convenient sometimes. The bug I was fixing yesterday was actually caused by the ViewState stopping working some time ago (when introducing the DropDownListCustom). Before that, the ole’ ViewState buddy had silently been doing its job, without anybody complaining. This should be remembered when we start talking about his disadvantages.
Further reading
Understanding ASP.NET View State: http://msdn.microsoft.com/en-us/library/ms972976.aspx
ASP.NET Page Life Cycle Overview: http://msdn.microsoft.com/en-us/library/ms178472.aspx



Leave a reply