Home > WebForms, c# > Making session variables a little easier to work with

Making session variables a little easier to work with

It’s been quiet on here for a while – that’s because I’ve been warped back to WebForms land where everything is craziness and it takes you half a day just to figure out wth is going on because you have to work with logic spread across a half dozen code behind files that all run to a couple thousand lines (no exaggeration!).

The app I am currently working on uses session variables a lot, and doesn’t clean them up very often, leading to odd behaviors due to stale state (among other things).

The first thing I do when I come across a page using session variables is extract them all into properties at the top of the page – this ensures those ugly string indexers are only in 2 places (the get and set) and you only have to write the cast once.  The problem I find with this is that to figure out if the session variable has a value or clean up the session variable I still have to address it using the string indexer, sure I can wrap that in a simple method call so I only have the indexer in 3 or 4 places, but when you have a page with 6 session variables, this starts to add a lot of cruft to the code behind.  What I really wanted was a simple way of adding a few methods to the property so I could do something like this…

int newValue = 0;
if( MySessionVar.HasValue )
{
  newValue += MySessionVar;
}
MySessionVar.Clear();

With a little bit of poking around, some generics and a simple implicit cast, I ended up with this:

using System;
using System.Web;

namespace Blog.Code
{
    ///<summary>
    /// Wraps a number of convenience methods around session variables allowing for a more fluent
    /// expression of the intent.
    ///</summary>
    ///<typeparam name="T">The type of the value to store in the session.</typeparam>
    public class SessionVariable<T> : IEquatable<SessionVariable<T>>
    {
        private readonly T _tempValueStore;
        private readonly string _sessionKey;

        ///<summary>
        /// The stored value or the default value for the type
        /// if there is no value associated with the sessionkey
        ///</summary>
        public T Value
        {
            get
            {
                object value = HttpContext.Current.Session[_sessionKey];
                if(value == null)
                {
                    return default( T );
                }

                return (T)value;
            }
        }

        ///<summary>
        /// Indicates if there is a value stored.
        ///</summary>
        public bool HasValue
        {
            get
            {
                return HttpContext.Current.Session[ _sessionKey ] != null;
            }
        }

        ///<summary>
        /// Creates a new SessionVariable to access the value stored in <paramref name="sessionKey"/>
        ///</summary>
        ///<param name="sessionKey">The key used to access the value in the session</param>
        public SessionVariable( string sessionKey )
        {
            _sessionKey = sessionKey;
        }

        ///<summary>
        /// Creates a new SessionVariable to store the value provided.
        ///</summary>
        ///<param name="value">The value to store.</param>
        /// <remarks>
        /// Value is not stored until <see cref="Store"/> is called.
        /// </remarks>
        public SessionVariable( T value )
        {
            _tempValueStore = value;
        }

        ///<summary>
        /// Stores the value in the session using the key specified.
        ///</summary>
        ///<param name="sessionKey">The key used to store the value.</param>
        public void Store(string sessionKey)
        {
            HttpContext.Current.Session[ sessionKey ] = _tempValueStore;
        }

        ///<summary>
        /// Removes the entry from the session.
        ///</summary>
        public void Clear()
        {
            HttpContext.Current.Session.Remove( _sessionKey );
        }

        ///<summary>
        /// Implicitly converts the specified value into a SessionVariable instance.
        ///</summary>
        ///<param name="value">The value to convert.</param>
        ///<returns>A SessionVariable instance holding the specified value.</returns>
        public static implicit operator SessionVariable<T>(T value)
        {
            return new SessionVariable<T>( value );
        }

        ///<summary>
        /// Implicitly converts the SessionVariable back to the type of the wrapped value.
        ///</summary>
        ///<param name="sessionVariable">The SessionVariable to convert</param>
        ///<returns>The wrapped value.</returns>
        public static implicit operator T(SessionVariable<T> sessionVariable)
        {
            return sessionVariable.Value;
        }

        public override string ToString()
        {
            return Value.ToString();
        }

        public bool Equals( SessionVariable<T> sessionVariable )
        {
            if ( sessionVariable == null )
            {
                return false;
            }
            return Equals( Value, sessionVariable.Value );
        }

        public override bool Equals( object obj )
        {
            if ( ReferenceEquals( this, obj ) )
            {
                return true;
            }
            return Equals( obj as SessionVariable<T> );
        }

        public override int GetHashCode()
        {
            return Value.GetHashCode();
        }
    }
}

Which can be used like this:

protected SessionVariable<string> SuccessMessage
{
    get
    {
        return new SessionVariable<string>("SuccessMessage");
    }
    set
    {
        value.Store("SuccessMessage");
    }
}

The only caveat is when accessing methods on the object you are wrapping, you have to use 1 of 2 approaches to get at the underlying value…

// Directly access the underlying value
SuccessMessage.Value.Split(...);

// Assign the wrapped value to a temporary variable to force the implicit cast
string successMessage = SuccessMessage;
successMessage.Split(...);

As the session is really just a Dictionary<string, object> you could probably make this work for any dictionary with a few simple changes, however I didn’t need that flexibility so I leave it as an exercise for the future.


Categories: WebForms, c#
  1. May 29, 2008 at 11:11 pm | #1

    This is pretty cool!!!

    When showing how to “directly access the underying value”, don’t you mean the following?
    SuccessMessage.Value.Split(…);

  2. Neal
    May 30, 2008 at 7:49 am | #2

    Yeh, thanks for catching that one Ori :)

  3. tnelson217
    September 3, 2008 at 11:19 am | #3

    I really like this approach, but have one question.

    I’m attempting to put the definition of my session variables inside of a class called “MySession”, so that I can access them like this:

    MySession.UserID

    But I can’t get it to work. Any suggestions? Am I trying to do something inappropriate?

    For example:

    public class MySession {

    public SessionVariable SuccessMessage
    {
    get
    {
    return new SessionVariable(“SuccessMessage”);
    }
    set
    {
    value.Store(“SuccessMessage”);
    }
    }
    }

    And then reference as MySession.SuccessMessage.

    It seems that if I do that, the Intellisense should pick up SuccessMessage and it does not.

  4. tnelson217
    September 3, 2008 at 11:27 am | #4

    OK, so sorry to bother y’all. Complete user error, forgot to instantiate my class.

  1. No trackbacks yet.