The Lazy Programmer

January 27, 2008

Typesafe session variables in ASP.NET

Filed under: Windows — ferruccio @ 4:17 pm
Tags: , ,

Lately I’ve been working on web applications using C# and ASP.NET and it struck me that since session variable are nothing more than hash tables that map strings to objects, they are prone to all sorts of programming errors.

  1. The variable "names" are strings that are passed as an index to the Session object. This has the same effect as having a language that does not require variables to be declared before use. You are always a single typo away from a hard to find bug. Also, Intellisense can’t help you when you’re trying to remember the name of particular session variable.
  2. If you try to use a session variable without setting it first, .NET will throw an exception. This usually results in session variable references being wrapped in try/catch blocks. Just in case.
  3. Session[] returns an object. So there is usually some sort of conversion to the actual desired type necessary. This is a minor point, but it does clutter the code with a lot of ToString(), Parse() and Convert*() method calls.

The solution I came up with was to create a class that just contains session variables. Each variable is implemented as a property with get and set accessors. For example, let’s say we need three session variables: an int, a bool and a string. We would define our class as:

using System;
using System.Web.SessionState;

public class AppSession
{
   private HttpSessionState session_;

   public AppSession(HttpSessionState session)
   {
      session_ = session;
   }

   public int count
   {
      set { session_["count"] = value; }
      get
      {
         try { return int.Parse(session_["count"].ToString()); }
         catch (Exception) { return 0; }   // initial value
      }
   }

   public bool init
   {
      set { session_["init"] = value; }
      get
      {
         try { return bool.Parse(session_["count"].ToString()); }
         catch (Exception) { return false; }  // initial value
      }
   }

   public string name
   {
      set { session_["name"] = value; }
      get
      {
         try { return session_["name"].ToString(); }
         catch (Exception) { return ""; }    // initial value
      }
   }
}


Once that’s all set up, whenever you need to access a session variable, all you need to do is instantiate an AppSession object and use its properties directly.

   AppSession sess = new AppSession(Session);

   sess.init = true;
   sess.name = "John Doe";
   sess.count = 12;

   if (sess.init)
      Console.WriteLine(string.Format("name: {0}, count: {1}", sess.name, sess.count);

Setting up each session variable is a little more tedious than just simply using the Session object, but I think the payoff is worth it. Session variables become more typesafe and a lot simpler to use. In any case, session variables are essentially global variables with persistence. It’s not wise to have too many of them.

Update: Feb 18, 2008

I’ve been told, quite rightly, that the try/catch blocks are unnecessary and can hurt performance. I’ve replaced my own code with the following type of construct which, I think, is actually more readable and compact.

public string name
{
  set { session_["name"] = value };
  get { return session_["name"] == null ? "" : session_["name"]; }
}

Update: March 23, 2008

I realized that I could simplify session variable usage even more by making all AppSession properties static. So instead of creating AppSession objects all over the place, I can now just use, for example, AppSession.name directly. The new AppSession class would look like:

using System;
using System.Web.SessionState;

public class AppSession
{
   private static HttpSessionState session_ = null;

   private AppSession()
   {
      // made this private so AppSession can't be instantiated
   }

   public static HttpSessionState session
   {
      set { session_ = value; }
   }

   public static int count
   {
      set { session_["count"] = value; }
      get { return session_["count"] == null ? 0 : int.Parse(session_["count"].ToString()); }
   }

   public static bool init
   {
      set { session_["init"] = value; }
      get { return session_["init"] == null ? false : bool.Parse(session_["count"].ToString()); }
   }

   public static string name
   {
      set { session_["name"] = value; }
      get { return session_["name"] == null ? "" : session_["name"].ToString(); }
   }
}


Since there is no longer a constructor to initialize the session_ object, I added a session property to do the initialization. The ideal place to set the session property is in the Session_Start() method in Global.asax.

Advertisements

13 Comments

  1. This is really great.

    So much better in the long run!

    Comment by Kirk — February 7, 2008 @ 11:17 am

  2. the use of try-catch in your session decreases performance!
    better check if the session variable is null instead.
    daniel-

    Comment by daniel — February 17, 2008 @ 4:09 am

  3. Just a minor point–your code above shows you bool.Parsing “count”–when it should be parsing init. πŸ˜‰

    ===
    nice catch. thanks.

    — ferruccio

    Comment by Darrel — April 8, 2008 @ 12:52 pm

  4. Thank You Very Much for writing such a reusable class…

    In March 28,2008 update you have mentioned that a property needs to be initialized in the Session_start() of global.asax.

    Can you tell us what is that property.Can you just add that code as well.

    Thanks.

    Comment by Pradeep — May 14, 2008 @ 12:50 am

  5. when i try to use this class in my code, something like

    Appsession.name=”Micheal”, it gives me object reference not set to instance exception.

    I have placed the Appsession class in the Appcode folder..

    I dont know the exact problem..

    Is there any thing I should add in Global.asax. Please let me know

    Comment by Deepu — May 14, 2008 @ 1:01 am

  6. Pradeep,
    Deepu,

    To add a global.asax to your project, select “Web Site|Add New Item…” from the visual studio menu and then select “Global Application Class”.
    This will create a global.asax file for you with a Session_Start() method already defined. You can then put the initialization in there. eg.

    AppSession.session = Session;

    — Ferruccio

    Comment by Ferruccio — May 14, 2008 @ 6:29 am

  7. To Deepu,

    if u r using appsession class without static property then u will have to create object of appsession class then only u can access property
    ex:
    Appsession obj;
    obj.name=”Micheal”,

    Comment by vivek — August 14, 2008 @ 5:56 am

  8. Hi.
    Wouldn’t declaring the HttpSessionState static affect the entire application? This’ll work if you only have one user at one time. But if another user starts a new session concurrently with yours, he/she would only overwrite your HttpSessionState with his/hers. Or did I miss the point of the “static” keyword entirely?

    It would be great if this will actually work. It’ll work out the painstaking process of checking across pages if one was using session keys consistently. I usually use const strings to achieve consistency in key names, but it’s still not typesafe.

    Comment by oragorn — September 15, 2008 @ 2:34 pm

  9. One other thing. I think you can do away with converting to string and parsing. Since you’re sure you passed the correct datatype to the session state, after checking for null, you may instantly cast the value back to the original datatype.

    Comment by oragorn — September 15, 2008 @ 2:46 pm

  10. Doh!

    You’re obviously right, Oragorn.
    I don’t know how I missed that making it static would limit it to one session. I’m going to have to plead temporary stupidity.

    Thanks for that catch.

    — Ferruccio

    Comment by Ferruccio — September 16, 2008 @ 10:25 pm

  11. quick note re: the final rendition of the code above. The concept is solid and the only problem that comes up is that accessing the Private (session_) is not guaranteed to point to a valid Session πŸ™‚

    I think it’s better (and I have implemented the code above using the following change …) to remove the private (session_) and simply have a Public Getter “session_” as follows :

       public static HttpSessionState session_
       {
          get { return HttpContext.Current.Session; }
       }
    

    this will ensure you are pointing at the correct Session ….
    ( … that’s actually almost what you had in your beginning code πŸ™‚
    As said – the rest is solid and I thank you for the head start

    b stensrud

    Comment by b stensrud — September 24, 2008 @ 12:06 am

  12. I’ve always thought you can only access Session though the page, thus the requirement to pass the Session to the session manager class, and thus prevents the use of static. Great job, b stensrud. This cleanly rounds off the objective of this article. Thanks.

    Comment by oragorn — October 1, 2008 @ 3:20 pm

  13. … glad to be of some small help πŸ™‚

    Comment by b stensrud — October 26, 2008 @ 12:39 pm


RSS feed for comments on this post.

Blog at WordPress.com.

%d bloggers like this: