ASP.NET provides mechanisms for storing information for a single user session or across multiple sessions. This is done using the HttpSessionState and HttpApplicationState classes. The Page class has Application and Session attributes to provide access to current objects. The simple way to access them is as following:

if (Session["FirstName"] == null) 
{ 
    LabelFirstName.Text = "FirstName"; 
} 
else 
{ 
    LabelFirstName.Text = 
         (string)Session["FirstName"]; 
} 
if (Session["LastName"] == null) 
{ 
    LabelLastName.Text = "LastName"; 
} 
else 
{ 
    LabelLastName.Text = (string)Session["LastName"]; 
}

This method has several drawbacks:

  • Type Safety: Session contains objects, so you need to cast.
  • Null reference: You must check, it might be null
  • Variable name: don’t use hard coded strings, beware of typos…

So Lets see the wrapper object and how it solves those issues:

public static class SessionWrapper 
{ 
    private static T GetFromSession<T>(string key) 
    { 
        object obj = HttpContext.Current.Session[key]; 
        if (obj == null) 
        { 
            return default(T); 
        } 
        return (T)obj; 
    }         

    private static void SetInSession<T>(string key, T value) 
    { 
        if (value == null) 
        { 
            HttpContext.Current.Session.Remove(key); 
        } 
        else 
        { 
            HttpContext.Current.Session[key] = value; 
        } 
    }         

    private static T GetFromApplication<T>(string key) 
    { 
        return (T)HttpContext.Current.Application[key]; 
    }         

    private static void SetInApplication<T>(string key, T value) 
    { 
        if (value == null) 
        { 
            HttpContext.Current.Application.Remove(key); 
        } 
        else 
        { 
            HttpContext.Current.Application[key] = value; 
        } 
    }         

    public static string FirstName 
    { 
        get { return GetFromSession<string>("FirstName"); } 
        set { SetInSession<string>("FirstName", value); } 
    }         

    public static string LastName 
    { 
        get { return GetFromSession<string>("LastName"); } 
        set { SetInSession<string>("LastName", value); } 
    }         

    public static User User 
    { 
        get { return GetFromSession<User>("User"); } 
        set { SetInSession<User>("User", value); } 
    } 
}

It contains a few generic private functions to read and write objects from/to the Session or the Application objects, and public methods to be used from the code to access required properties.Note that the use of HttpContext.Current requires a valid request, or Current might be null!

This wrapper provides a safe typed access from all over the application, one place to define all objects that might be stored in the session. If you want to move objects from the Session to other storing mechanism this would be solved in the wrapper only. The usage is also much easier:

LabelFirstName.Text = SessionWrapper.FirstName; 
LabelLastName.Text = SessionWrapper.LastName;

Note that you can add any initialization code or default values in the wrapper:

public static string FirstName 
{ 
    get 
    { 
        string firstName = GetFromSession<string>("FirstName"); 
        if( string.IsNullOrEmpty(firstName)) 
        { 
            firstName = "FirstName"; 
            SetInSession<string>("FirstName", firstName); 
        } 
        return firstName; 
    } 
    set { SetInSession<string>("FirstName", value); } 
}

Tags :

19 Responses to “Why Should You Wrap Your ASP.NET Session Object”


  1. AdamJTP

    Said on May 7, 2008 :

    We use something like this in TeamLive – it also has the advantage that you can deal with session timeouts (and authenication hasn’t timed out) in one place.

    An alternative (but not necessarily better) is to use extension methods on HttpSessionState so that new developers (who may be used to dealing with session directly) notice the session facade.

    e.g. Once the developer familiar with vanilla Session has typed in “Session.” – the intellisense may prompt them to wonder what the GetFirstName() method does?

    e.g.
    public static class SessionHelper
    {
    private const string _sessKeyFirstName = “FirstName”;

    ///your code but with a “this” param
    public static string GetFirstName(this HttpSessionState session)
    {
    string firstName = GetFromSession(_sessKeyFirstName);
    if( string.IsNullOrEmpty(firstName))
    {
    firstName = _sessKeyFirstName;
    SetInSession(_sessKeyFirstName, firstName);
    }
    return firstName;
    }

    //all your stuff
    private static T GetFromSession(string key)
    {
    object obj = HttpContext.Current.Session[key];
    if (obj == null)
    {
    return default(T);
    }
    return (T)obj;
    }

    private static void SetInSession(string key, T value)
    {
    if (value == null)
    {
    HttpContext.Current.Session.Remove(key);
    }
    else
    {
    HttpContext.Current.Session[key] = value;
    }
    }
    }

    Ideally we’d be able to use extension properties (“.FirstName” (as you’ve done) seems more natural than “.GetFirstName()”) – but I suppose methods have the advantage of being able to take parameters later on – but I guess it’s down to dev team coding preference.

    e.g.:

    ///Optional update if name has been
    //updated by different user
    //or data feed?
    GetFirstName(this HttpSessionState sess,bool refreshSessionFromDb)
    {
    }

    ///default case
    GetFirstName(this HttpSessionState sess)
    {
    return sess.GetFirstName(false);

    }

  2. Daniel

    Said on May 7, 2008 :

    Another option would be to store a single “Plain Old Class Object” in session or application:

    internal class MyAppSession
    {
    public string FirstName{get;set;}
    public string LastName{get;set;}
    public User User{get; set;}

    public static MyAppSession Current
    {
    get
    {
    if (HttpContext.Current.Session[“MyAppSession”] == null) HttpContext.Current.Session[“MyAppSession”] = new MyAppSession();
    return (MyAppSession)HttpContext.Current.Session[“MyAppSession”];
    }
    }
    }

    This makes the properties easier to declare, and you can initialize their values in the constructor.

  3. Brian Lowry

    Said on May 7, 2008 :

    While I like the idea, I don’t think its good future-proofing to make the session type-safe in this way. It makes more sense to me to have session accessed from within a domain object. What happens if your requirements change and you can’t use Session anymore? You haven’t successfully abstracted away the location of the stored variable by calling static methods on a SessionWrapper class.

    Instead, I would prefer:
    internal class Employee
    {
    public string FirstName { get {…} set {…} }
    public string LastName { get {…} set {…} }

    And use the get and set to access the session value. Additionally, there should be some form of naming convention for the session key so that there are no collisions… so add in:

    public const string FirstNameKey = “Employee.FirstName”;
    public const string LastNameKey = “Employee.LastName”;

    This keeps you from having to worry about typos and such.

  4. Brian Lowry

    Said on May 7, 2008 :

    I also wanted to add that the first part of the SessionWrapper class would be good to use when accessing them in the manner I stated above… i just wouldn’t put FirstName, LastName, etc. as part of the Session class.

  5. Will

    Said on May 7, 2008 :

    I use a slightly different pattern:
    http://statestreetgang.net/post/2008/01/Generics-and-the-Session-State.aspx

    I like passing in a delegate to a method that will store and return the default value. The same pattern can be used for the viewstate, the cache, or any other similar construct.

  6. Mooglegiant

    Said on May 20, 2008 :

    This is very helpful for me. However when I was trying it out on a sample web app, I keep getting a “Specified cast is not valid” when trying to get a int from the session.

    I checked though and the value is a “1”. I’m just not sure what the problem is with the casting.

  7. Thanks

    Said on July 5, 2008 :

    Thank You!!!!

    Helped me alot :P

  8. Pradeep

    Said on July 25, 2008 :

    Great post. Was able to use the code without any problem. Thanks for other comments too!

  9. Golem

    Said on September 19, 2008 :

    Nice job. I’ve implemented a similar mechanism into a project I’m working on.

    One thing I’ve run into is that at times, there may be a need to create an “ad hoc” session variable, where the key name is dynamically generated based on a variable, i.e. Session[“Preference_” + userID];

    I have not been able to come up with a solution for this that fits into the SessionWrapper class, where the keys need to be hard-coded into the class.

  10. Chris Marisic

    Said on September 29, 2008 :

    Go Go one line lazy loading get statement

    private static T GetFromSession(string key)
    {
    return (T) (HttpContext.Current.Session[key] ?? (HttpContext.Current.Session[key] = default(T)));
    }

  11. Chris Marisic

    Said on September 29, 2008 :

    Proper declaring of Set Method:

    private static void SetInSession(string key, T value)
    {
    if (Equals(value, default(T)))
    { HttpContext.Current.Session.Remove(key);
    }
    else
    { HttpContext.Current.Session[key] = value;
    }
    }

    The only really weird case is if you store primitive types in the session using this wrapper like int x, to remove x you need to pass in 0 which is default(int) but I think that’s a fair trade off since with the other declaring you would need to try to pass in SetInSession(key, null) which wouldn’t work because null isn’t a valid value of int.

  12. Vijay

    Said on January 23, 2009 :

    Hi

    I just need a clarification …. when using the above wrapper method, cant you think like is your server memory will get blocked if more users log in.

    Please let me know how to over come that

  13. Yves

    Said on April 26, 2009 :

    Do not forget… when accessing HttpContext.Current.Application
    the code must be Thread Safe. I guess you know why gentlemen.

  14. Jaimir Guerrero

    Said on May 19, 2009 :

    Hi,

    thanks for sharing your idea.

    We implemented it in our project, but when we published our web site on iis 7.0 and two or more users enter concurrently, last user’s data overwrite the others users data, mainly when the session variable was use inside of objectdatasource.

    could you please help me?,

    thanks

    Jaimir G.

  15. Stormy

    Said on August 19, 2009 :

    On the surface, this appears to be a really nice solution, using generics and a nice static class to manage sessions. But like many of these attempts at abstracting out built-in ASP.NET objects and collections, these new classes or objects end up adding more maintenance time to what is already a simple system.

    Example, if I want to add a new session that returns an array, to do that I now have to open up the static class and add the new property. If you have 5 developers adding lots of these, you create a bottleneck immediately. You also add a new maintenance layer. For example, what if I need the “Firstname” session but need it cast out as an encrypted FirstName. I now either have to create a new Firstname property in the static class (ie mroe maintenance) or recast it again in my webpage. Thats why many of these abstraction layers fail. Too much convolution.

    What I do is keep things simple, by building a simple Sessions class that has a “Get” “Set” and other utility methods. I dont cast anything, but return objects, and cast when used in my webpages. I never return nulls as those are checked one time in the class. I also set defaults in all sessions if null, using a simple enum in the class for one of serveral types (example 0 for integers, “” for strings, etc). This allows me to use the native library adding sessions on the fly with any name I need and any type I need. I never return types or pass in generics. I pass in and return objects, always.

    This allows you to build rich Session objects as needed and return and cast or convert as needed without the overhead of constantly managing and updating class properties. That added complexity just adds more overhead. I sday, always use the power of the ASP.NET framework libraries as they stand when possible. Saves me tons of time. Keep it simple!

  16. Venkat

    Said on February 5, 2010 :

    I have small when we using datasets.

    I have a dataset stored in session and want check if the dataset is null or not if it is null then redirect the user to error page otherwise display values from the dataset.

    How i can i approach this when using wrapper session like above

3 Trackback(s)

  1. May 8, 2008: Dew Drop - May 8, 2008 | Alvin Ashcraft's Morning Dew
  2. May 14, 2008: How to wrap the ASP.net session state « .Net Braindrops
  3. Aug 13, 2008: links for 2008-08-13 [delicious.com] | andy brudtkuhl

Post a Comment