Click here to Skip to main content
11,932,734 members (55,311 online)
Click here to Skip to main content
Add your own
alternative version


38 bookmarked

Maintaining State Per Page in ASP.NET Web Applications

, 17 Apr 2007 CPOL
Rate this:
Please Sign up or sign in to vote.
This article describes an approach to build ASP.NET Pages that maintain their state when the user navigates between them.

class diagram


This article discusses an approach to build ASP.NET pages that maintain their state between requests.

Let me give an example: A user, Hugo, selects a year in the year-selection DropDownList on a page. Unfortunately, he decides to navigate to another page of my web application before continuing to enter data on my page. Later on, Hugo returns to my page and wants to continue entering data. Normally, he would have to start from scratch, but because my page has stored its state, Hugo can continue as he has expected.

What's so special about my approach?

Actually, nothing. But I like designs that help me build programs faster and better. As you will see further on, I use the Session hashtable of the HttpContext as normal, but I have built some wrappers and helpers that simplify my programming task.

Using the code

The StatePage class is a base class for all my pages that want to make use of their own state. It is derived from System.Web.UI.Page. Through the properties of the StatePage, all derived pages have access to two state objects:

  1. PageState: Contains the state of a single page.
  2. InterPageState: Contains the data that is shared by multiple pages.

Both state objects are read from the Session when the page is initialized, and stored back to the Session when the page is rendered.

The InterPageState is used to pass values from one page to another. A common scenario is that a user can select something on a page that is also present on several other pages (for example, a year selection that is present on multiple reporting pages). After selecting it on one page, it would be great if the selection would be the same for all pages all together. Therefore, I called this class InterPageState - the state shared between pages.

Actually, this is how you would use the Session normally, but I prefer using the InterPageState to access the Session directly, because I don't have to play around with key constants and casting operations. This is the same "pattern" as The Essential Geek describes in his article "Wrap Those Session Variables!". Furthermore, I can distinguish between state that is relevant to controls on a page and state that is "real" Session state like information about the user etc.

The PageState objects are handy because they can be used in the context of a single page. I use PageStates to restore the state of a page to the state before the user left the page the last time. PageStates lead to better readability and less complexity compared to one single wrapper for the Session bag because they contain only the state data used for one single page.

Interesting code parts

Loading and saving of the page specific states is provided by the PageState base class, as shown below:

/// <span class="code-SummaryComment"><summary></span>

/// Defines the state of a <span class="code-SummaryComment"><see cref="StatePage"/>.</span>

/// <span class="code-SummaryComment"></summary></span>

/// <span class="code-SummaryComment"><remarks></span>

/// This class is used to store information about the state of a page in 

/// order to restore it when the user navigates back to this page.


/// The <span class="code-SummaryComment"><see cref="PageState"/> objects are stored in the </span>

/// <span class="code-SummaryComment"><see cref="System.Web.SessionState.HttpSessionState"/> bag.</span>


/// Classes can be direved form this class to hold specific data for a 

/// <span class="code-SummaryComment"><see cref="StatePage"/>.</span>

/// <span class="code-SummaryComment"></remarks></span>

public class PageState
    /// <span class="code-SummaryComment"><summary></span>

    /// Retrieves the <span class="code-SummaryComment"><see cref="PageState"/> object for the </span>

    /// specified <span class="code-SummaryComment"><see cref="StatePage"/></span>

    /// <span class="code-SummaryComment"></summary></span>

    /// <span class="code-SummaryComment"><param name="page"></span>

    /// The page for which the state is retrieved.

    /// <span class="code-SummaryComment"></param></span>

    /// <span class="code-SummaryComment"><returns></span>

    /// State information stored earlier in the current session.

    /// <span class="code-SummaryComment"></returns></span>

    public static PageState GetPageState(StatePage page)

    /// <span class="code-SummaryComment"><summary></span>

    /// Stores information about the state of a page into the 

    /// <span class="code-SummaryComment"><see cref="System.Web.SessionState.HttpSessionState"/> bag.</span>

    /// <span class="code-SummaryComment"></summary></span>

    /// <span class="code-SummaryComment"><param name="page">StatePage</param></span>

    /// <span class="code-SummaryComment"><param name="pageState">State object</param></span>

    public static void SetPageState(StatePage page, PageState pageState)
        System.Web.HttpContext.Current.Session[page.GetType().FullName] = 

The key for the Session entry is the fully qualified type name of the Page. This allows that several pages can share the same StatePage class (class, not instance!)

Loading and saving of the state of a page is handled by the StatePage base class. It uses the methods provided by the PageState class (shown above) to access the correct state from the Session.

public class StatePage : Page
    /// <span class="code-SummaryComment"><summary></span>

    /// Resets the cache statistics.

    /// Retrieves the current <span class="code-SummaryComment"><see cref="PageState"/> for this </span>

    /// <span class="code-SummaryComment"><see cref="StatePage"/>.</span>

    /// <span class="code-SummaryComment"></summary></span>

    /// <span class="code-SummaryComment"><param name="e"></param></span>

    protected override void OnInit(EventArgs e)

        if (System.Web.HttpContext.Current != null)
            // get page state for this page

            this.pageState = PageState.GetPageState(this);
            if (this.pageState == null)
                this.pageState = CreatePageState();

            // don't get confused by the next couple of lines of code. 

            // this is not the way I do this in may applications. I'm using

            // an object manager but this is part of an other article ;-)

            // so just get it dirty from the Session bag

            this.interPageState = (InterPageState)Session["InterPageState"];
            if (this.interPageState == null)
                this.interPageState = new InterPageState();
                Session.Add("InterPageState", this.interPageState);

    /// <span class="code-SummaryComment"><summary></span>

    /// Extracts the <span class="code-SummaryComment"><see cref="PageState"/> from the page by calling </span>

    /// <span class="code-SummaryComment"><see cref="PullState"/> and stores it in the session.</span>

    /// Calls <span class="code-SummaryComment"><see cref="Control.OnPreRender"/>.</span>

    /// <span class="code-SummaryComment"></summary></span>

    /// <span class="code-SummaryComment"><param name="e"></param></span>

    protected override void OnPreRender(EventArgs e)
        if (System.Web.HttpContext.Current != null)
            PageState.SetPageState(this, this.PageState);


    ... other code

If no PageState is present in the Session, then a new one is instantiated. The default implementation of the virtual CreatePageState method returns null. To define a page specific PageState, the derived page has to override the CreatePageState method - this is shown in the sample page further below.

Accordingly, the InterPageState is accessed from the session. The InterPageState is included in this sample just to emphasize the difference between the state per page and the state that is beyond the scope of a page. Hopefully, I'll find some time to write an article about my instance managing pattern that is used to access the InterPageState and other singleton instances. The above sample is a quick and dirty implementation in order to have a running sample application.

Before the page is rendered, there is the last change to writes values to the PageState. This is accomplished in a derived class by overriding the PullState method (an example is shown below). After the state is defined, it is stored to the Session by the PageState class.

The following diagram summarizes the steps for loading, accessing, updating, and saving a PageState.

life time of PageState instances

Example stateful page

The following example shows a page that is derived from my StatePage and uses its functionality to store a year value and a text value:

public partial class Page2 : StatePage
    /// <span class="code-SummaryComment"><summary>Just a small helper</summary>.</span>

    /// <span class="code-SummaryComment"><remarks></span>

    /// I normally use Dependency Injection for intitalizing member objects 

    /// but that's part of another article ;-)

    /// <span class="code-SummaryComment"></remarks></span>

    private DropDownListHelper dropDownListHelper = 
        new DropDownListHelper();

    /// <span class="code-SummaryComment"><summary></span>

    /// Load data.

    /// <span class="code-SummaryComment"></summary></span>

    /// <span class="code-SummaryComment"><remarks></span>

    /// I override the event invoker method instead of registering the Load

    /// event because I don't like objects registering events of themselves.

    /// <span class="code-SummaryComment"></remarks></span>

    /// <span class="code-SummaryComment"><param name="e"></param></span>

    protected override void OnLoad(EventArgs e)

        if (!IsPostBack)
            // try to select the value from the InterPageState


            // restore the text of the TextBox

            this.txtText.Text = this.PageState.Text;

    /// <span class="code-SummaryComment"><summary></span>

    /// Create the PageState for this page.

    /// <span class="code-SummaryComment"></summary></span>

    /// <span class="code-SummaryComment"><returns></returns></span>

    protected override PageState CreatePageState()
        return new Page2PageState();

    /// <span class="code-SummaryComment"><summary></span>

    /// Provide typed access to the PageState of this page.

    /// <span class="code-SummaryComment"></summary></span>

    private new Page2PageState PageState
        get { return (Page2PageState)base.PageState; }

    /// <span class="code-SummaryComment"><summary></span>

    /// Save the state of the page. This is the second way to accomplish 

    /// that. See Page1 for the other implementation.

    /// <span class="code-SummaryComment"></summary></span>

    protected override void PullState()

        this.InterPageState.Year = this.ddlYear.SelectedValue;
        this.PageState.Text = this.txtText.Text;

When the page is loaded, I restore the saved values from the last visit on this page. If this is the first visit, then the controls are set to the default values defined in the corresponding PageState.

This page overrides the CreatePageState method to instantiate an instance of the class Page2PageState that will hold the state information for this class (the text value). Additionally, the PullState method is overridden in order to save the values from the controls to the state: the year value is stored in the InterPageState so other pages that have a year selection, too, can initialize them with this value (the user has to specify a value once in the application and not on every page again and again). The text value is stored in the state of the page so it can be restored when the user returns to this page.


Okay, you may say to yourself that this article describes nothing that is new to you. Maybe because you are using a pattern similar to mine, or you do the same directly with the Session bag.

You may be right with that, but in a Web Application with some hundreds of thousand of lines of code and more than thirty (non-static) pages, I'm very happy to have a wrapped access to session data, especially the context based approach of the PageState classes.

Finally, please post your thoughts in the message area Smile | :)

Source of the code

The sample code is extracted from a web application that I wrote for bbv Software Services AG.

bbv logo

Thanks for letting me write about it.


  • 2007-04-17 - Initial version.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Urs Enzler
Architect bbv Software Services AG
Switzerland Switzerland
Urs Enzler is working for bbv Software Services in Switzerland as a Software Architect.

Blogger at

You may also be interested in...

Comments and Discussions

Questionwhu u need to use [Serializable] in your coding Pin
koolll13-May-12 18:15
memberkoolll13-May-12 18:15 
GeneralExcellent Pin
Member 284702422-Jul-09 2:11
memberMember 284702422-Jul-09 2:11 
GeneralGood Article - My Scenario Pin
engineerachu5-Mar-09 23:26
memberengineerachu5-Mar-09 23:26 
GeneralRe: Good Article - My Scenario Pin
Urs Enzler13-Mar-09 23:08
memberUrs Enzler13-Mar-09 23:08 
GeneralPerformance Pin
BULU19824-Jun-08 14:10
memberBULU19824-Jun-08 14:10 
GeneralRe: Performance Pin
Urs Enzler20-Jun-08 5:49
memberUrs Enzler20-Jun-08 5:49 
GeneralVery good article Pin
ReginaJensen8-Apr-08 4:58
memberReginaJensen8-Apr-08 4:58 
GeneralRe: Very good article Pin
Urs Enzler20-Jun-08 5:39
memberUrs Enzler20-Jun-08 5:39 
GeneralVery Interesting Pin
Normand3728-Apr-07 3:31
memberNormand3728-Apr-07 3:31 
GeneralA great article Pin
Henry Nguyen19-Apr-07 5:48
memberHenry Nguyen19-Apr-07 5:48 
GeneralVery Nice Pin
JohnDeHope318-Apr-07 8:55
memberJohnDeHope318-Apr-07 8:55 
GeneralRe: Very Nice Pin
Urs Enzler18-Apr-07 20:54
memberUrs Enzler18-Apr-07 20:54 
QuestionWindows Workflow ? Pin
xyxyxyxy18-Apr-07 1:09
memberxyxyxyxy18-Apr-07 1:09 
AnswerRe: Windows Workflow ? Pin
Urs Enzler18-Apr-07 1:21
memberUrs Enzler18-Apr-07 1:21 
QuestionSession Bag? Pin
Dewey17-Apr-07 22:10
memberDewey17-Apr-07 22:10 
AnswerRe: Session Bag? Pin
Urs Enzler17-Apr-07 22:24
memberUrs Enzler17-Apr-07 22:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.151126.1 | Last Updated 18 Apr 2007
Article Copyright 2007 by Urs Enzler
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid