Brendan Tompkins

Sponsors

The Lounge

Wicked Cool Jobs

News

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
A Better ASP.NET State Pattern

Creating a better way to manage ASP.NET state has been talked about quite a bit.  I’ve posted about it a few times, as have others.  A couple of weeks ago Raymond brought the topic up again, and it got me thinking that the way I've been doing it could probably be improved upon.  Today I needed to look at it again for our public web site, so I thought that it was a good time for a rewrite. 

If you have a look at my StateClassBase Redux  there’s a number of problems with the implementation. For one, it’s a poor use of OO.  Yes, there is a base class, but it just contains a bunch of overloaded methods.  In fact, having a bunch of overloaded methods is usually a good indication that your design isn’t all that great.  For another, it was cumbersome to use, and required that it be initialized in your code before you use it.  Initializing the class in your OnInit worked okay sometimes, but could also be buggy in other situations, like when your control was dynamically loaded.  The new version lazy loads itself, via a singleton-ish Instance property, which helps sort out these issues.

It also wasn’t easy to re-use. If I wanted to add another back-end session storage mechanism, it involved modifying the base class itself.  What was I thinking?

Recent Updates (2/24/05):

  • Added  [Serializable] to the class and [XmlIgnore] to the Instance
  • Made the SessionStateObject class Abstract

So, here’s my new and improved StateBase class:

  [Serializable]public abstract class StateBase

  {

    protected string stateKey;

    private object instance;

 

    /// <summary>

    /// Gets the instance.

    /// </summary>

    /// <value></value>

    [XmlIgnore]public virtual Object Instance

    {

      get

      {

        // Lazy Load

        if(instance == null)

        {

          // Try to restore

          Object o = Restore();

          if(o != null)
          {

             instance = o;
             return o;

          }

          // Create a new instance of the derived type

          Type type = this.GetType();

          instance = Activator.CreateInstance(type);

        }

 

        return instance;

      }

    }

 

    /// <summary>

    /// Gets or sets the state key.

    /// </summary>

    /// <value></value>

    public string StateKey

    {

      get { return stateKey; }

      set { stateKey = value; }

    }

 

    /// <summary>

    /// Creates a new <see cref="StateBase"/> instance.

    /// </summary>

    /// <param name="stateKey">State key.</param>

    public StateBase(string stateKey)

    {

      this.stateKey = stateKey;

    }

 

    /// <summary>

    /// Stores this instance.

    /// </summary>

    /// <returns></returns>

    public abstract void Store();

 

    /// <summary>

    /// Removes this instance.

    /// </summary>

    /// <returns></returns>

    public abstract void Remove();

 

    /// <summary>

    /// Restores this instance.

    /// </summary>

    /// <returns></returns>

    public abstract Object Restore();

 

  }

And here’s a derived class that sores the state in Session. 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.

public abstract class SessionStateObject : StateBase

  {

    /// <summary>

    /// Creates a new <see cref="SessionStateObject"/> instance.

    /// </summary>

    /// <param name="stateKey">State key.</param>

    public SessionStateObject(string stateKey) : base(stateKey)

    {}

 

    /// <summary>

    /// Stores this instance.

    /// </summary>

    /// <returns></returns>

    public override void Store()

    {

      System.Web.HttpContext.Current.Session[stateKey] = this;

    }

 

    /// <summary>

    /// Removes this instance.

    /// </summary>

    /// <returns></returns>

    public override void Remove()

    {

      System.Web.HttpContext.Current.Session.Remove(stateKey);

    }

 

    /// <summary>

    /// Restores this instance.

    /// </summary>

    /// <returns></returns>

    public override Object Restore()

    {

        return System.Web.HttpContext.Current.Session[stateKey];

    }

  }

And here’s how to use it in your code, simply derive from the SessionStateObject, adding any members you want to keep track of your state.

    /// <summary>

    /// Object for maintaining state

    /// </summary>

    public class SomeControlsState : SessionStateObject

    {

      public SomeControlsState() : base("SOMECONTROL_STATE")

      {}

 

      public new SomeControlsState Instance

      {

        get

        {

          return (SomeControlsState)  base.Instance;

        } 

      }

 

      private ShippingContainerCollection containers;

 

      public ShippingContainerCollection Containers

      {

        get { return containers; }

        set { containers = value; }

      }

    }

Now, assuming that you’ve created an instance of state (you can now do this in-line in your class) to save your state, just call Store();

state.Instance.Containers = someService.Instance.GetShippingContainerCollection();

state.Instance.Store();

Using in on subsequent postbacks is even easier:

ShippingContainer sc = state.Instance.Containers.Find(Convert.ToInt32(e.CommandArgument));

No more worrying about calling Restore() unless you specifically need to.  Hope you find this useful.  I really would like some feedback to this.  If this can be done better, I want make this thing sing!

-Brendan


Posted Wed, Feb 23 2005 3:07 PM by Brendan Tompkins
Filed under:

[Advertisement]

Comments

Raymond Lewallen wrote re: A Better ASP.NET State Pattern
on Thu, Feb 24 2005 6:10 AM
I like this model much better, but what do you do if you have a userId that you need to store in session as an Int32? Are you creating a class for that too? Are you creating a class for each and every object that you want to maintain state for? Each control on a page for viewstate? Its just seems so heavy, yet very useful the way its designed. What does your PreInit or Page_Load code look like for creating and dealing with all of these classes when you have a control-heavy page for say 20 controls? Does it get hard for you to maintain at that point?
Brendan Tompkins wrote re: A Better ASP.NET State Pattern
on Thu, Feb 24 2005 6:24 AM
Raymond,

You can use one State class for the entire application, or one per control (which is my preference).

If I needed to keep track of a userId, I'd probably create a stateclass, with the userId member, then use it. My reasoning? Because someday, I'm probably going to have to keep track of something else on that control, and now I have a place to put it.

There's no intialization code for this, since it's lazy loaded. All you have to do is declare a class-level variable of your state type, and then always access it through the "Instance" member.
Raymond Lewallen wrote re: A Better ASP.NET State Pattern
on Thu, Feb 24 2005 7:43 AM
You declare a class-level variable for each control you are going to maintain state for, I understand that, but they way I understand it is you don't have a singleton "instance" for managing state, you have an "instance" for managing state per object you want to manage. And if you did have a singleton instance for the entire state for the entire application, you run into what I deal with in my pattern, which is a sometimes heavy state instance with many members that I don't use all the time and doesn't scale easily enough. I certainly understand the reasoning for doing it this way you show here, and like the approach, but don't you worry about the maintenance of it all? Don't think I don't like what you have, because I do. I like it better than my approach. I just play a great devil's advocate. :) I have to update my presentation material to include your new state class pattern to present on March 7th. I'm excited to present this stuff and get some feedback for us both.
Brendan Tompkins wrote re: A Better ASP.NET State Pattern
on Thu, Feb 24 2005 7:49 AM
"but don't you worry about the maintenance of it all?"

Yes! I worry a lot about maintenance, which is exactly why I think it's better to encapsulate a control's state within (or close to) the control itself.

When each control is responsible for it's own state, then it gets de-coupled from the entire application, which then makes it more portable and maintainable, IMO.

Now, some state management makes sense at the macro level, so I put this stuff in a state class that lives in my PageBase class. For everything else, I try te encapsulate it as much as possible in the control.
TrackBack wrote OdeToCode Links For Feb 27th
on Sun, Feb 27 2005 6:27 PM
TrackBack wrote OdeToCode Links For Feb 27th
on Sun, Feb 27 2005 6:54 PM
TrackBack wrote A Resharper Live Template for SessionStateObject
on Fri, Mar 4 2005 1:33 PM
Charles Fisher wrote re: A Better ASP.NET State Pattern
on Tue, Mar 8 2005 1:42 PM
hey hey...

Pretty good stuff Brendan! I hope there is an additional class (utility or functionality included in the .aspx) that cleans up the state behind you unless you're doing your own housekeeping.

Using the example Raymond and yourself discussed previously, there are 20 controls with this state management. When they move on to another webform or process in which the information is not necessary, the state will remain bloated until it's manually cleaned up or the session ends.

Hmm... maybe I need to revisit the original blog first before I put my foot in my mouth. :)

Really great stuff... just wish I was working on a project that gave me time to develop more.. elegant solutions to some of the problems we face.
Brendan Tompkins wrote re: A Better ASP.NET State Pattern
on Tue, Mar 8 2005 1:50 PM
Yep, you do have to watch out for anything you put into Session. I've coded implementation of a strongly-typed ViewState, and I have to wrap a blog post around it some day. This has advantages/disadvantages, but it does take care of the memory concerns.
TrackBack wrote re: ASP.NET Page Inheritance - Base Page Classes in your Web Applications
on Mon, Mar 14 2005 1:26 PM
TrackBack wrote A Strongly-Typed Cookie State Object
on Tue, Mar 15 2005 8:09 AM
TrackBack wrote A Strongly-Typed Cookie State Object
on Tue, Mar 15 2005 8:25 AM

Add a Comment

(required)  
(optional)
(required)  
Remember Me?
Devlicio.us