2.2 ViewState
In the previous section, we stated that you can mark
any
HTML element with the
runat
=server
attribute to make it accessible programmatically on the server. This at first seems implausible because there are many HTML elements whose values are not sent in the body of a
POST
request. For example, consider the page shown in Listing 2-3, which shows the implementation of a simple
accumulator
. When the
user
posts the page with a numeric value in the input element, the value is added to a running total. The running total is
maintained
in a server-side span element, whose value is extracted with each post-back and added to the value submitted by the user, and the resultant sum is assigned back into the
InnerText
attribute of the server-side span element.
Listing 2-3 Accumulator Page
<!-- Accumulator.aspx -->
<%@ Page Language="VB" %>
<html>
<script runat=server>
Protected Sub Page_Load(src As Object, e As EventArgs)
If IsPostBack Then
Dim op1 As Integer = Integer.Parse(_op.Value)
Dim op2 As Integer = Integer.Parse(_sum.InnerText)
_sum.InnerText = (op1+op2).ToString()
End If
End Sub
</script>
<body>
<form runat=server>
<h2>ASP.NET accumulator page</h2>
<input size=2 type=text id=_op runat=server/>
Sum:<span id=_sum runat=server>0</span>
<p>
<input type=submit value="Add" />
</p>
</form>
</body>
</html>
This page works in spite of the fact that the contents of the span, whose value we depend on for maintaining the total, is not passed back as part of the default post action of the client-side form. The only control in our page's form whose contents is sent back when the form is posted is the
_op
input element. Or is it?
Listing 2-4 shows the HTML that is rendered the first time this page is
requested
. Notice that in addition to all the explicit elements that were in our .aspx page, there is a hidden input element named
__VIEWSTATE
. The value of this element is a base64-encoded string that acts as a state repository for the page. Any elements on a page whose contents are not implicitly posted back via the standard form
POST
mechanism have their values saved to and restored from this hidden field. It is also used to propagate supplemental state for controls ”for example, what prior value was stored in a control so that server-side change notifications can be issued. While the technique of propagating state using hidden input fields is common practice in Web applications, ASP.NET takes it a step further and uses it to unify the server-side control model by ensuring that all elements
marked
with
runat=server
retain their state across post-backs.
Listing 2-4 Accumulator Page Rendering
<html>
<body>
<form name="_ctl0" method="post"
action="accumulator.aspx" id="_ctl0">
<input type="hidden" name="__VIEWSTATE"
value="dDwtMTE3NzEwNDc2Njs7PvcRil1nMNe70yha9afq+YEvj46N" />
<h2>ASP.NET accumulator page</h2>
<input name="_op" id="_op" type="text" size="2" />
Sum:<span id="_sum"></span>
<p>
<input type=submit value="Add" />
</p>
</form>
</body>
</html>
Figure 2-4
demonstrates
a request sequence for our accumulator page. Each time a request is serviced by the accumulator page, the current value of the
_sum
span element is restored from the hidden
__VIEWSTATE
field. And when the page
renders
its response, the current value of the server-side span element representing the
_sum
field is placed into the
__VIEWSTATE
field so that the
next
time the page is posted back, the value of the
_sum
can be restored to its most recently displayed value.
Figure 2-4. Accumulator Page Request Sequence
|