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
StateClassBase Redux

I've been having a good discussion on how best to encapsulate your ASP.NET page state over on Raymond's blog.  Raymond has advocated adding a State object to your PageBase class that has slots for each important session object that you're going to use (correct me if I'm wrong Raymond)..

The nice thing about this approach, is that 1) it makes your session info strongly typed, and 2) it is always there, easily accessible. The downside to this, IMO, is that 1) you end up with a bloated state object, with many possibly unused members, depending on the what the end-user is doing and 2) any controls that depend on this information become tightly coupled to your PageBase Class

The solution I've been using for a while works well, but I think it needs some more thinking. I've created a StateClassBase, which I've posted about before, but here's the latest incarnation:

  [Serializable()]

  public class StateClassBase

  {

    private string _stateKey;

 

    public string stateKey

    {

      get

      {

        return _stateKey;

      }

      set

      {

        if (_stateKey == value)

          return;

        _stateKey = value;

      }

    }

 

    public StateClassBase(string stateKey)

    {

      _stateKey = stateKey;

    }

 

    public virtual object StateRestore(System.Web.UI.StateBag ViewState)

    {

      if(ViewState[_stateKey] != null)

        return ViewState[_stateKey];

      else

        return null;

    }

 

    public virtual object StateRestore(System.Web.HttpApplicationState State)

    {

      if(State[_stateKey] != null)

        return State[_stateKey];

      else

        return null;

    }

 

    public virtual object StateRestore(System.Web.SessionState.HttpSessionState ViewState)

    {

      if(ViewState[_stateKey] != null)

        return ViewState[_stateKey];

      else

        return null;

    }

 

    public virtual object StateRestore(System.Web.Caching.Cache ViewState)

    {

      if(ViewState[_stateKey] != null)

        return ViewState[_stateKey];

      else

        return null;

    }

 

    public virtual void StateStore(System.Web.UI.StateBag ViewState)

    {

      ViewState[_stateKey] = this;

    }

 

    public virtual void StateStore(System.Web.SessionState.HttpSessionState ViewState)

    {

      ViewState[_stateKey] = this;

    }

 

    public virtual void StateStore(System.Web.HttpApplicationState State)

    {

      State.Lock();

      State[_stateKey] = this;

      State.UnLock();

    }

 

    public virtual void StateStore(System.Web.Caching.Cache ViewState, System.TimeSpan timeToExpire)

    {

      ViewState.Insert(_stateKey, this, null, System.DateTime.Now + timeToExpire, TimeSpan.Zero);

    }

 

 

    public virtual void StateRemove(System.Web.UI.StateBag ViewState)

    {

      ViewState[_stateKey] = null;

    }

 

    public virtual void StateRemove(System.Web.SessionState.HttpSessionState ViewState)

    {

      ViewState[_stateKey] = null;

    }

 

    public virtual void StateRemove(System.Web.HttpApplicationState State)

    {

      State.Lock();

      State.Remove(_stateKey);

      State.UnLock();

    }

 

    public virtual void StateRemove(System.Web.Caching.Cache ViewState)

    {

      ViewState.Remove(_stateKey);

    }

 

    // Removes all instances in session

    public static void StateRemove(System.Type typ, System.Web.SessionState.HttpSessionState ViewState)

    {

      string [] keys = new string[ViewState.Keys.Count];

      for(int i = 0; i < ViewState.Keys.Count; i++)

      {

        keys[i] = ViewState.Keys[i];

      }

 

      foreach(string key in keys)

      {

        if(ViewState[key] != null && ViewState[key].GetType() == typ)

        {

          ((StateClassBase)ViewState[key]).StateRemove(ViewState);

        }

      }           

    }

  }

To use this in a control (any System.Web.UI.Control including Page) you derive from this base class, and add your strongly typed members.

    ///

    /// Object for maintaining UsersOnlineControl state

    ///

    [Serializable]

    public class UsersOnlineControlState : StateClassBase

    {

      public UsersOnlineControlState() : base("UsersOnlineControl_STATE")

      {}

 

      private bool chatOn = true;

 

      public bool ChatOn

      {

        get { return chatOn; }

        set { chatOn = value; }

      }

 

    }

Then, in your OnInit method, and set a local member of your derived type to the instance.

      // Initialize the State Class

      this.stateclassbase = (UsersOnlineControlState) new UsersOnlineControlState().StateRestore(this.Page.Session);

      if (this.stateclassbase == null) this.stateclassbase = new UsersOnlineControlState();

The cool thing about it is that you can store your state in Session, ViewState, Application, or Cache. The other nice advantage is being able to decouple your controls from your page base class. If you have a control that depends on being on your page base to get the state, then it's tightly coupled with your page. If the control just manages it's own state, like this, it can be placed on any page.

Now, this thing does need some work, which is why I wanted to post this.  For one thing it'd be nice not to have to do the boxing and unboxing, or at least not have to code it every time.  Also, it'd be nice to not have to instance it in your OnInit method.  Possibly a re-design with some lazy loading, and some better OO work could help.

-Brendan


Posted Thu, Feb 3 2005 8:48 AM by Brendan Tompkins
Filed under:

[Advertisement]

Comments

Scott Galloway wrote re: StateClassBase Redux
on Thu, Feb 3 2005 10:22 AM
Brendan, in Firefox, this post messes up the main feed.
Brendan Tompkins wrote re: StateClassBase Redux
on Thu, Feb 3 2005 10:33 AM
Ooops.. Yes it did. I fixed this.. Thanks! There's a long story here abou how I switch back and forth between IE and Firefox, and how I'm rapidly becoming an IE hater, and now I have zillions of browser windows open at any given time while I try to get used to tabbed browsing, and how IE still seems to pop open from time to time, and I'm trying out SourceToHtml, and on and on. But I wouldn't want to bore you. :)
Darrell wrote re: StateClassBase Redux
on Thu, Feb 3 2005 11:46 AM
One thing I would change is to make the StateRestore method always return a non-null object. This would make the following line of code unnecessary in the OnInit, having moved it into the StateRestore:
if (this.stateclassbase == null) this.stateclassbase = new UsersOnlineControlState();

This maintains encapsulation as your page does not need to know about the state restoration mechanism.
Raymond Lewallen wrote re: StateClassBase Redux
on Fri, Feb 4 2005 7:10 AM
Brendan,

I've been looking over your code and kind of working on a few things with it in my head. Question: are you creating a type that inherits the StateBaseClass for each control or object you want to store state information for? As far as the boxing and unboxing, you can take care of that easily enough, but scaling it for each type you want to deal with wouldn't be much fun, so I can see why you leave it as just object. I like the implementation, and will probably take yours and implement a few ideas, rather than take mine and implement your ideas. Yours is a better starting point for where I/we probably want to go with it. Still working on how we can fit the best of both together. I really would like to examine how to reduce the amount of code required for yours though, but thats probably just because I'm spoiled using my implementation.
Brendan Tompkins wrote re: StateClassBase Redux
on Fri, Feb 4 2005 7:55 AM
"are you creating a type that inherits the StateBaseClass for each control or object you want to store state information for"

Yes, usually I'm working with a Control, or Page, and need to store state for just that control. I subclass this stateclass, and add members to it.

The problem of how to return the instance without boxing from the StateRestore method is the tricky part. Could do the boxing within the subclass itself, right, but that would be a pain, might as well just do it once in the OnInit of your page.

PS. Base class should be abstract..
TrackBack wrote How do you like CodeBetter.com so far?
on Mon, Feb 14 2005 5:56 PM
TrackBack wrote How do you like CodeBetter.com so far?
on Mon, Feb 14 2005 5:58 PM
TrackBack wrote State Class Management Presentation on March 7th
on Wed, Feb 16 2005 11:45 AM
TrackBack wrote A Better ASP.NET State Pattern
on Wed, Feb 23 2005 12:13 PM

Add a Comment

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