A couple of weeks ago, I posted about A Better ASP.NET State Pattern,
which essentially demonstrates a strongly-typed wrapper base class for
storing ASP.NET state. In this post, I showed one implementation
of this pattern, which used Session to store the state. I hinted
that it would be easy to use other back end storage mechanisms for your
state objects:
Note that you can create one that stores state in ViewState, or
Application or Cache or in the Database, or on your cell phone. The
point is, you just derive from StateBase, and implement the abstract methods.
This week I’m going to do a series of three posts to
demonstrate different back end storage mechanisms for storing Page
State in Cookies, Cache, and ViewState. Today, I’m going to start with a Strongly-typed cookie wrapper class, called CookieStateObject.
[Serializable]
public abstract class CookieStateObject : StateBase
{
public CookieStateObject()
{
}
protected System.DateTime expires = System.DateTime.Now.AddYears(1);
/// <summary>
/// Creates a new <see cref="ViewStateObject"/> instance.
/// </summary>
/// <param name="stateKey">State key.</param>
public CookieStateObject(string stateKey) : base(stateKey)
{}
/// <summary>
/// Stores this instance.
/// </summary>
/// <returns></returns>
public override void Store()
{
string serializedVersion = SerializationHelper.XmlSerialize(this);
System.Web.HttpContext.Current.Response.Cookies[stateKey].Value = System.Web.HttpUtility.UrlEncode(serializedVersion);
System.Web.HttpContext.Current.Response.Cookies[stateKey].Expires = expires;
}
/// <summary>
/// Removes this instance.
/// </summary>
/// <returns></returns>
public override void Remove()
{
System.Web.HttpContext.Current.Response.Cookies.Remove(stateKey);
}
/// <summary>
/// Restores this instance.
/// </summary>
/// <returns></returns>
public override Object Restore()
{
if(System.Web.HttpContext.Current.Request.Cookies[stateKey] != null)
{
string serializedVersion = System.Web.HttpContext.Current.Request.Cookies[stateKey].Value;
return SerializationHelper.XmlDeSerialize(System.Web.HttpUtility.UrlDecode(serializedVersion), this.GetType());
}
return null;
}
}
This class Serializes the object to XML, UrlEncodes the XML, and stores it as a cookie. You can get a copy of An XML Serialization Helper Class here. Here’s an example of an implementation of the CookieStateObject:
public class CameraState : CookieStateObject
{
/// <summary>
/// Creates a new <see cref="CameraState"/> instance.
/// </summary>
public CameraState() : base("Camera_STATE")
{}
private ArrayList m_arrCameraID = new ArrayList();
private ImageWidth m_imaCameraImageWidth = ImageWidth.Small;
/// <summary>
/// Gets the instance.
/// </summary>
public new CameraState Instance
{
get { return (CameraState) base.Instance; }
}
public ImageWidth CameraImageWidth
{
get
{
return m_imaCameraImageWidth;
}
set
{
m_imaCameraImageWidth = value;
}
}
public ArrayList CameraIDs
{
get
{
return m_arrCameraID;
}
set
{
m_arrCameraID = value;
}
}
}
And here’s an example of how this class can be used:
private CameraState state = new CameraState();
private void AddSelectedToView()
{
this.state.Instance.CameraIDs.Clear();
foreach(ListItem item in this.chkCameras.Items)
{
if(item.Selected)
{
this.state.Instance.CameraIDs.Add(item.Value);
}
}
this.state.Instance.CameraImageWidth = ImageWidth.Thumbnail;
this.state.Instance.Store();
}
A couple of things to note here. Cookies have a maximum size of 4KB. My
Serialized, UrlEncoded Camera object above is about 1.3K
when filled with the maximum amount of data that I expect it
to ever hold. You should be very aware of this maximum,
and make sure you’re well below it in practice, however this
is true of any data you intend to store, no matter where you decide to
persist it. If you run into space limitations, you can
tweak the serialized Xml using attributes.
Using a strongly-typed wrapper for state objects can greatly reduce
runtime errors, and make your code easier to read and mantain over
time. Hope you find this useful!
-Brendan