Persisting Page State in ASP.NET 2.0By Scott Mitchell
There are different types of state in an ASP.NET web application: page state, session state, and application state. Page state is state that is specific to a particular user's visit to a particular page and is commonly used to remember any programmatically changed state of the page across postbacks. Session state is state remembered for a particular user across all visits and all pages during their session. Application state is state that is shared across all users on all pages and all requests and is often used for caching data or information that is applicable to all users visiting the site.
Page state, commonly referred to as view state, is persisted in a hidden form field, by default. When a page is being rendered, any programmatic changes to a control's state is saved to the page's overall view state. During the rendering stage, this view state is serialized into a base-64 encoded hidden form field and sent down to the client's browser. On postback, the view state data is sent back to the web server, where it is deserialized and returned to the appropriate Web controls in control hierarchy so that they may re-establish their state as it was prior to the postback.
View state provides a slick way to remember state in a stateless client-server model and it happens underneath the covers without any extra effort from page developers. The downside of view state, however, is that in certain situations the view state can grow to be exceedingly large. A large view state requires a longer page download time since it bloats the total web page size and also affects the postback time, since the entire view state content must be posted back to the web server along with the other form fields.
It is possible, however, to persist view state to an alternate medium. Such customizations were possible in
ASP.NET version 1.x by overriding a couple of methods in the
Page class. ASP.NET 2.0 makes customizing page state persistence
easier as this logic is handled through a separate class. In this article we'll explore the built-in page state persistence options
in ASP.NET 2.0, which includes the ability to persist page state to session state rather than through a hidden form field.
We'll also look at how to extend the functionality to provide a custom persistence scheme. Read on to learn more!
A Quick Look at the Page Lifecycle
Each time an ASP.NET page is requested, it goes through a series of events that make up its lifecycle. The end goal of a page's lifecycle is to render its contents (typically HTML), which is then returned to the client that made the request (typically a browser). Rendering is the last stage of the page's lifecycle, and before rendering the page constructs its control hierarchy, reloads page state, raises any necessary Web control-related events (such as a Button's
Clickevent), and saves the page state, among other things. During this lifecycle, any changes to the page's state must be remembered across postback else any such changes will be lost.
For example, imagine a Web page with a Label Web control whose
BackColor property is not set. Also on this
page is a Button Web control. Now imagine that this page's
Page_Load event handler has code like the following:
This code sets the Label control's
BackColor property to Red on the first page visit. On subsequent postbacks,
Page.IsPostBack will be True and therefore the code assigning the
BackColor property will not execute.
By eyeballing this code it's clear that when first visiting the page, the Label will render with a red background. But what
happens when the Button is clicked, causing a postback? The code that sets the Label's
BackColor property doesn't
run, but the rendered Label's background remains red. This is because this property assignment is remembered across postbacks
in the page's state.
On each visit to the page, during the save page state stage of its lifecycle, the
Page asks the controls on the page:
"Excuse me, but do you have any changed state?"
The Label then raises his hand and sheepishly says, "Ahem, sir? Sir, over here. I have changed my
to Red." The
Page jots this information down.
Page produces its final rendering, it takes those notes it jotted down - the changed state - and persists
that information to some sort of backing store. By default, the notes are serialized into a base-64 encoded string and persisted
to a hidden form field named
__VIEWSTATE, but the serialization and backing store can be modified, as we'll see
in this article.
New to ASP.NET 2.0, the
PageStatePersisterclass defines the base functionality needed to persist page state to some backing store. This class is associated with a particular
Pageinstance and provides
Savemethods (among other members). The
PageStatePersisterclass is abstract, meaning it can't be used directly but rather must be extended. There are two classes that extend
PageStatePersisterin the .NET Framework 2.0:
HiddenFieldPageStatePersister- the default page state persisting logic. Uses a hidden form field to persist page state.
SessionPageStatePersister- stores page state in a session variable, which can be used to reduce the bloat associated with persisting page state as a form field.
PageStatePersisterclass, opting to persist page state to a database or to text files on the web server's file system or through some other means. Later on in this article we'll look at how to persist page state to the web server's file system later on in this article, but first let's take a closer look at
Persisting Page State to Session
The .NET Framework 2.0 includes
SessionPageStatePersisterclass, which persists page state to session. In particular, this page state persister, when used, tracks the page state for each page visit for a user in her session store using two session variables:
Queueobject that maintains the names of the session variables that maintains the page state. This object just serves as bookkeeping - it just maintains the list of session state variable names. that store the actual page state. By default, only the last nine page state instances are saved in session, but you can configured your application, raising or lowering this value. Keep in mind that a request to any page (including postbacks) constitutes a "visit", so visiting a single page and posting back eight times would add nine entries to the session state queue and nine additional session state variables.
__SESSIONVIEWSTATETicksAsBase16Number- stores the serialized page state. TicksAsBase16Number takes the number of 100-nanosecond intervals that have elapsed since midnight on January 1, 0001 and the current date and time and converts it into a hexidecimal number. Again, by default only nine of these values are stored in session at a time. Upon adding the tenth item, the oldest one is removed from session state.
SessionPageStatePersisterclass stores the value of TicksAsBase16Number in the
__VIEWSTATEhidden form field. On postback, the
Loadmethod examines the passed-back TicksAsBase16Number value and retrieves the appropriate page state from the session variable
To change the default page persistence logic from the hidden form field approach to using the
you can either override the
property or use an adapter. The download available at the end of this article shows how to override the
using a base page class, with the germane code shown below.
For information on using an adapter, see the example at the bottom of this
The following code (taken from this article's download) shows how to override the
configuring it to use the
SessionPageStatePersister class instead of the default
A history of nine page state values are saved in session because of the browser's Back button. Imagine a user visits
a page and does a number of postbacks. On each postback, a new TicksAsBase16Number value is calculated and a new
session variable is created holding that particular postback instance's page state. Now, envision what would happen if
SessionPageStatePersister class did not store a history of states. Say that our user, after making a number
of postbacks, hits the Back button a few times. Their browser now displays an earlier page from the browser cache with
an earlier TicksAsBase16Number value!. After hitting Back a few times, the user does a postback, sending an
old TicksAsBase16Number value back to the server. Since no history of page state was kept, the page state cannot be found
in session, and page state is lost.
To customize the size of the page state maintained in history, which dictates how many times the user can go Back with
things still working as expected, add the
Web.config, specifying a value for the
historySize attribute like so:
Another downside of using session state to persist page state is that session state is volatile. That is, it automatically is abandoned after a user's session "expires," which occurs, by default, 20 minutes after a user's last activity. So if a user visits a page, does some postbacks, then goes to lunch and comes back 30 minutes later, on the following postback the page state will be lost since the session will have been abandoned ten minutes ago. Also, some users may have their browsers configured to not accept session-level cookies, which means the default session implementation will not work for them, meaning that they will not be able to persist page state across postbacks.
To see the
SessionPageStatePersister class in action, its effect on shrinking the hidden
form field size, and the contents of session state when this method is employed, download the support material available
at the end of this article.
PageStatePersister: Persisting Page State to the Web Server's File System
The download at the end of this article includes a class in the
FileSystemPageStatePersisterthat persists the page state to a file on the web server's file system. In particular, these page state files are stored in the
~/StateFiles/folder with the file name
TicksAsBase16Number-SessionID.vsand contain the serialized page state. The SessionID is included in the file name since these files are generated for all users visiting the site.
FileSystemPageStatePersister class stores the page's state
to a new file with each "visit" to the page. The file name is remembered across postbacks through a hidden form field,
__SKM_VIEWSTATEID, much like how the
SessionPageStatePersister stores the TicksAsBase16Number
__VIEWSTATE hidden form field.
The code for
FileSystemPageStatePersister is fairly straightforward. Let's look at
The method starts by determining the file name to save the page state to and then determines the full physical file path using
Server.MapPath. Next, the page state, which is represented via the
objects, is serialized to the specified file path using the configured
determines how the page state is serialized and the default
StateFormatter serializes page state into a base-64 encoded
Next, a hidden form field named
__SKM_VIEWSTATEID is added. Its value is the file name that contains the page state.
This form field markup is injected into the rendered markup by adding a LiteralControl to the
Page's Web Form.
Load method grabs the file name from the hidden
__SKM_VIEWSTATEID form field and then deserializes
the page state, assigning it back to the
The complete code plus a demo of this custom page state persister is available in the download at the end of this article.
View State Persistence in ASP.NET 1.x
PageStatePersisterclass is new to ASP.NET version 2.0. In ASP.NET version 1.x, view state persistence could be customized by extending the
Pageclass and overriding its
LoadPageStateFromPersistenceMediummethods. As these methods' names imply, they are responsible for saving page state to some backing store and loading it back, and are synonymous to the
Loadmethods, respectively. For a more in-depth look at view state as well as ASP.NET 1.x implementation specifics, refer to my article Understanding ASP.NET View State.
In ASP.NET 1.x, page state was stored to a hidden form field by default, although this behavior could be modified by overriding a couple methods in the
Pageclass. With ASP.NET 2.0, page state persistence can be handled by any class that extends the
PageStatePersisterclass. The .NET Framework 2.0 ships with two built-in persisters:
HiddenFieldPageStatePersister, which persists page state to a hidden form field (the default); and
SessionPageStatePersister, which persists state in session. As we saw in this article, it's possible to create custom page state persisters and plug them into an ASP.NET 2.0 application.