Wrap your ASP.Net session state into a more meaningful object.

Posted on December 8, 2009 
Filed Under .Net Code, CSharp, Web Development

I’ve tried to eliminate as much session state as possible as I know that it can cause some issues, especially in a server farm environment. However, there are quite a few times that I just need to have it, and I really doubt this small application is going to be hosted in a farm environment. This application is connected to a WCF service, and I really needed to eliminate round trips without using caching since some of this data is somewhat time sensitive, but it still needs to be available across a few page views. Instead of hitting the WCF service numerous times, I save the data in session state.

The way most people seem to have done session state (at least in just random searches on the internet and in sample code), you see this:

  HttpContext.Current.Session["SomeData"] = myData;

There is nothing wrong with this. It works. Is it maintainable? Sort. Is it a potential problem? YES! What happens if you do this somewhere:

  myData = HttpContext.Current.Session["SomData"];

Obviously you are going to get a null object back and possibly an error depending on other factors. You will probably find the problem during your automated tests (you do have automated tests right?) or at minimum find it during your own testing. The problem is, sometimes things like this will slip past if they are in infrequently used parts of a system that no one bothers to check for 3 or 4 versions that pass.

So in searching around I found various posts on how to wrap your session state into a more manageable object so that typos don’t creep up and bite you on the backside. Some of the examples went way over what I needed to do and some were way too simple to make sense for me.

So here is what I did (if I happened to have stolen your code, sorry, but it happens in software).

First I created my Current Session class to store everything and I made it static since Session itself is a static object.

  public static class CurrentSession
  {
    private static HttpSessionState LiveSession
    {
      get { return HttpContext.Current.Session; }
    }
  }

This simple gives me a class that has access to the current session through a private variable called LiveSession.

Inside this class, I created another class for the CurrentUser since I needed to track the current logged in user (this user has data from the web service, so I’m not using asp.net authentication methods).

    public static class CurrentUser
    {
      public static bool IsLoggedIn
      {
        get 
        { 
          bool? logIn = GetUserItem(UserData.LoginState);
          if (!logIn.HasValue) logIn = false;
          return (logIn.Value);
        }
        set { SetUserItem(UserData.LoginState, value); }
      }

      public static FamilyData CurrentFamily
      {
        get { return (GetUserItem(UserData.Family)); }
        set { SetUserItem(UserData.FamilyInfo, value); }
      }

      private static T GetUserItem(UserData key)
      {
        T data = (T)LiveSession[Enum.GetName(typeof(UserData), key)];
        return (data);
      }

      private static void SetUserItem(UserData key, T data)
      {
        if (data == null)
          LiveSession.Remove(Enum.GetName(typeof(UserData), key));
        else
          LiveSession[Enum.GetName(typeof(UserData), key)] = data;
      }

      public enum UserData
      {
        Family,
        LoginState
      }
    }

Now, some explanation and why I did it the way I did. I could have just made my public variable have the getter and setter access the Session object directly. My typo chances would have been minimized by the fact that it’s only in two spots that I need to type it, but there is still a chance. So I created myself an enum that I can use to specify which sets of data I am saving or retrieving. I use the enum’s string value as the session object name, so all I have to do is make sure my enums never use the same name. In my RLC (Real Life Code) I use much longer enums, like CalendarFilterMonth or CalendarFilterDay, for example. In the above example, I use LoggedInUserFamily in place of just Family. While it may be long, intellisense always gets it right for me with just a few keystrokes.

The GetUserItem and SetUserItem simple save and retrieve from the LiveSession object. I use Type generics to tell the functions what type I am saving and retrieving for ease of use. My type casting never has to be done now. I tell it what I want and that’s what I will get in return.

The best part about this, is to add more, all I need to do is copy and paste a property and change a few of the options, maybe add an enum, and now I’m done. I don’t have to worry about typo’s and I can organize my session object however I want.

To use it, I just do this anywhere in my application:

  if (!CurrentSession.CurrentUser.IsLoggedIn)
     RedirectToLogin();
  else
     if (CurrentSession.CurrentUser.CurrentFamily.NeedsProfileUpdate)
        RedirectToUpdate();

Since NeedsProfileUpdate is part of my FamilyData class, I can access that directly!

Comments

Leave a Reply