Click here to Skip to main content
Click here to Skip to main content

State Management

By , 23 Sep 2003
 

Introduction

How to persist objects in a web application between each request? How to send objects between pages? How to easily access the persisted objects? This article demonstrates a set of best practices and sample codes that I gained during web applications development.

I created a State class that is responsible for storage of persisted objects. The State object is implicitly stored in HttpSession, therefore can be treated as a wrapper of the Session. The State has two static methods: get and set which allows you to get and set an object from and to the State. The methods are intended to be used in property get and set methods therefore the names. Each of the persisted object is internally stored in a Hashtable under two parts key: class name and property name.

Here you can find few samples of how to use the State class.

Persisting objects between requests

There is very often a need to persist some object stored on page between requests. The object can be stored in viewstate, but I do not recommend it as it involves serialization of the object and sending it to the client.

Solution 1: Private property that stores value in State.

Such private property that stores its value in State allows you to retrieve a previously set value. There can be many of such properties on one page. Each of them is stored under different key in the State.

Here is a sample property used to store an object between requests:

private string persistedText
{
    get { return (string)State.get(); }
    set { State.set(value); }
}

Solution 2: [Persist] attribute on a field that should be retained.

The Persist attribute is created to mark fields that should be saved and restored from State.

Here is a sample how to mark a field to be persisted between requests:

[ Persist ]
private string previouslySent;

To make the attribute working, special code must be run on page init to restore the fields' values from State:

private void Page_Init(object sender, System.EventArgs e)
{
    Persister.LoadState(this);
}

To store the fields' values in State, Persister should be also called in Page_Unload event:

private void Page_Unload(object sender, System.EventArgs e)
{
    Persister.SaveState(this);
}

Sending objects between pages

The problem with sending objects between pages is that there is only one Page object available at a time. There is no way to get a page that will be displayed on the next request and change its properties.

Solution: a static property that stores value in State.

Such property is available from any place, and does not require object to be created at the time it is set. We are used to static properties that store application level objects, but thanks to using State, it is session level storage (two sessions can set the same property and each of them retrieves its own value).

Here is a sample property that can be used to pass string between pages:

public class Addressee : System.Web.UI.Page
{
    public static string IncomingText
    {
        get { return (string)State.get(); }
        set { State.set(value); }
    }
}

And here is a sample code that sends some text to Addressee.aspx:

Addressee.IncomingText = "the sent text";
Response.Redirect("~/Addressee.aspx");

Storing session level objects

By the session level object, I mean an object that is session specific and should be available from any place in the application, e.g. user name. I do not recommend storing the objects directly in session. It causes problems, as it does not give strongly typed access to the object and it is very similar to global variables in old, procedural programming (and involves the same difficulties).

Solution: one class that will give strongly typed access to all the session level objects and store them in State.

Such a class will contain one static property for each of the objects. The property will store and retrieve the object value from State.

Here is a sample class that gives access to session level objects:

public class SessionContext
{
    public static string UserName
    {
        get { return (string)State.get(); }
        set { State.set(value); }
    }
}

Storing application level objects

The application level object is an object that can be implemented by Singleton Design Pattern. Simply speaking, it is application global variable. Such a variable can be stored in one of three places: static variable, Application object or Cache object. I do not recommend any of them as all the ways are quite similar.

Here you can find sample of how to store application level object in application state.

public static object GlobalObject
{
    get { return HttpContext.Current.Application["some unique key"]; }
    set { HttpContext.Current.Application["some unique key"] = value; }
}

How to avoid sending ViewState to client

I found that in some cases serialized viewstate took half of the sent page.

Solution: store viewstate in State.

The Page object gives you two methods: SavePageStateToPersistenceMedium and LoadPageStateFromPersistenceMedium. When you override those methods on your page, you can store the viewstate wherever you need. The viewstate will not be serialized and sent to the client.

Here is sample code that should be added to Page class to store viewstate in State.

private object __VIEWSTATE
{
    get { return State.get(); }
    set { State.set(value); }
}

override protected void SavePageStateToPersistenceMedium(object viewState)
{
    this.__VIEWSTATE = viewState;
}

override protected object LoadPageStateFromPersistenceMedium()
{
    return this.__VIEWSTATE;
}

Best practices summary

Remember: Always use strongly typed access to an object that you persist.

Remember: Create your own Page and UserControl base classes. Place the Persister call in there and add the viewstate storing.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Marcin Celej
Web Developer
Poland Poland
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Question@class ?memberbachand20 Jun '06 - 8:03 
What is the significance of the '@' on your @class parameter?
 
Thanks in advance, bachand
AnswerRe: @class ?memberMarcin Celej20 Jun '06 - 10:01 
class is a keyword so it can't be used as a variable name. Keywords can be prefixed with @ and used as any other variable / parameter.
 
Best regards,
Marcin Celej
Generalreuse componentmemberjoachim stephan9 Nov '05 - 3:42 
Hi,
 
after several testing I found your ASP.NET compenent State Management very useful and would like to use it for a (commercial) application. Herewith I want to ask you if you agree with this. Please contact me at joachim.stephan@aspentech.com.
 
Best Regards,
 
Joachim Stephan
 
joachim.stephan@aspentech.com
Questionhelp! what's wrong with my code?memberYour details have been updated28 Aug '05 - 21:54 
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Xml;
using System.Text;
 
namespace WebUI.kp.mulu
{
///
/// ShowKP 的摘要说明。
///
public class ShowKP : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
if(!Page.IsPostBack)
{
// 在此处放置用户代码以初始化页面
string kpid = "121";
string startTime = DateTime.Now.ToString();
string xmlPath = Session["rootPath"].ToString();
string strFileName = xmlPath + "\\time.xml";
XmlTextWriter _XmlTextWriter = new XmlTextWriter(strFileName,Encoding.UTF8);
_XmlTextWriter.Formatting = Formatting.Indented;
_XmlTextWriter.Indentation = 4;
_XmlTextWriter.WriteStartDocument();
_XmlTextWriter.WriteStartElement("time");
_XmlTextWriter.WriteStartElement("kptime");
_XmlTextWriter.WriteElementString("kpid",kpid);
_XmlTextWriter.WriteElementString("starttime",startTime);
_XmlTextWriter.WriteElementString("endtime",startTime);
_XmlTextWriter.WriteEndElement();
_XmlTextWriter.WriteEndElement();
_XmlTextWriter.WriteEndDocument();
_XmlTextWriter.Flush();
_XmlTextWriter.Close();
 

// XmlDocument doc = new XmlDocument();
// string xmlName = Request["xmlName"];
// doc.Load(xmlPath + @"\" + xmlName);
// Response.Write(doc.OuterXml.Replace("?>","?>"));
 
}
}
 
private void Page_Unload (object sender , System.EventArgs e)
{
string endTime = DateTime.Now.ToString();
string filePath = Session["rootPath"].ToString();
string strFileName = filePath + "\\time.xml";
XmlDocument xdoc = new XmlDocument();
xdoc.Load(strFileName);
XmlNode xNode = xdoc.SelectSingleNode("//endtime");
xNode.InnerText = endTime;
xdoc.Save(strFileName);
}
 

#region Web 窗体设计器生成的代码
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
//
InitializeComponent();
base.OnInit(e);
}
 
///
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
///
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
this.Unload += new System.EventHandler(this.Page_Unload);
}
#endregion
}
}

GeneralSession on new HTTPHandlermemberGuillermo Jimenez28 May '05 - 17:27 
Ok, by now I have realized that when you drop the default Page Handler provided by ASP.NET you lose the ability to have the Session object created automatically by the HTTPPipeline.
 
I added an ASPX file to my application, restored the ASPX handler and run it just to see if I got the session back...I did.
 
Then I explored the possibility of forcing the HTTPApplication to raise the required event for the SessionState module to kick in but no luck...
 
What do I need to do to get a session object in spite of the page not inheriting from the usual HTTP object?
 

Guillermo Jimenez
 

GeneralHttpContextmemberskb33317 Mar '05 - 5:56 
Could anyone tell me if I can rely on using the Context.Items collection when requests are processed by 2 different servers in a web farm?
GeneralRe: HttpContextmemberGuillermo Jimenez28 May '05 - 17:18 
Shared state between members of a web-farm is possible only because of the existence of a state-server.
 
Unfortunately the Cache doesn't have the option of saving its contents to ASP.NET StateServer--only the Session object has that option. However there is nothing to stop you from creating your own StateServer...in fact the ASP.NET one is nothing but a Windows Service.
 
Bear in mind however that you also need to provide the logic for syncing up what contents belong to which applications, plus the logic to have an HTTPModule do the retrieval and update on each of the machines in the web-farm.
 
Guillermo Jimenez

GeneralWhy not use Cache objectsussAnonymous1 Nov '04 - 7:08 
I'm confused why you recommend against using the Cache object for storing application wide values. I'm not clear that you suggest a good alternative to ApplicationState or Cache. Those two are quite different by the way. The .NET Cache supports dependencies, memory scavenging to release cached values if memory is scarce and support for callbacks from the cache. Those are all very useful features that provide strong performance options.
GeneralRe: Why not use Cache objectmemberMarcys1 Nov '04 - 8:00 
Hi,
 
I do recommend using Cache or Application object and I do not present any alternative for them in this article. Maybe my english is not the best so I did not state it clearly. I saw some lacks in the ASP in sending objects between pages or storing values between requests. That was the origin of the article and I really think that using the Application or Cache is very useful though in my opinion there is almost no difference between them and a static property. Anyway I encourage you to store any relevant data in the application level storage mechanisms and I do it sometimes (not too often as unfortunatelly nature of web applications is that it cannot be cached and is always dynamic)
 
Best Raegards,
Marcys
GeneralRe: Why not use Cache objectmembermiltash24 Jul '07 - 4:32 
Static variable is 500 times or more faster than those objects.
 
check this lnik to know more details http://www.devx.com/vb2themax/Tip/18845

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

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 24 Sep 2003
Article Copyright 2003 by Marcin Celej
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid