Blog

ASP.Net State Management And Why You Shouldn’t Use Session Directly

ASP.Net provides out-the-box several nice (although not new) features to manage your application’s state, the Session and Application objects. The Session and Application objects are also among the first things learned by students of almost any web programming framework but while they are true in their usefulness it doesn’t mean you should use them directly, in this post I’ll explain why and how to work around its shortcomings.

  1. Session and Application items aren’t strong typed
    That means you need to do castings all over the place. While casting is safe and ensures consistency it’s not always infallible and sometimes can create ambiguous situations. Also, somewhere along the code you might assign the wrong object type, for example Session[“item”] = TextBox1.Text where the expected item’s type was integer.
  2. The default value is null
    Along with casting you must check before casting the value, this adds not only a condition for each call but also makes you implement the extra code to get/set the default value in some cases. Some times you don’t need a default value, but when you do the most common path is to set the item to that value either using memory to store something that is… a default!… or placing the default value in several places in your project making it harder to update later. It might seem a bit too much worrying about memory usage on Session items, but sometimes you need to store serialized objects that eat a lot of memory, so I believe that making sure we delete it when we don’t need it it’s a good practice.
  3. The right name
    It’s easy to forget the right name for an item or introduce a typo that can be difficult to trace, and since the item’s key is case insensitive it becomes a bit harder to replace the key name later across the entire project.
  4. Changing the state management is a nightmare
    Sometimes you find that you need to change the state management for a particular set of items. You might want to store/retrieve something in a configuration file, a database or even a web service and then the only solution is to track down each usage and update it. Unfortunately you don’t even can have the compiler to help…
  5. Cascade updates and deletes
    Its hard to keep track of relationships between each item. For example, on log out you might set the “IsSignedIn” item to false and you might also want want to delete the user name, user id, etc… Doing this kind of logic can be “centralized” on a single project-wide “Logout()” method but that is limited to a particular use and isn’t “item-based”.

The solution I use is to create a static class that has all the “global” variables in use. By using this approach not only can I rename Session items at will but I’ll have intellisense and compiler errors to help me. Also, by centralizing everything around one class I can make sure that changing the state management for each item is easy and painless, be it from/to configuration files or a database.

Another aspect of mapping the items to properties is that it makes things easy from a security perspective since you can add checks to the getter/setter of the properties (for example to catch cross-site scripting hack attempts).

Of course this approach solves the other problems I enumerated, for example, I don’t check for null or do cascade deletes anywhere else. I kinda like to call this the “ORM for State Management” πŸ˜›

Anyway… the code for an example implementation:

	public static partial class DataPersistence
	{
		public static HttpApplicationState Application
		{
			get
			{ return HttpContext.Current.Application; }
		}

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

		#region Authentication and Identity
		public static bool IsSignedIn
		{
			get
			{ return Session["IsSignedIn"] == null ? false : (bool)Session["IsSignedIn"]; }
			set
			{
				if (value)
					Session["IsSignedIn"] = value;
				else
				{
					Session["IsSignedIn"] = null;
					SignedInUserName = null;
				}
			}
		}

		public static string SignedInUserName
		{
			get
			{ return Session["SignedInUserName"] == null ? string.Empty : (string)Session["SignedInUserName"]; }
			set
			{ Session["SignedInUserName"] = value; }
		}
		#endregion
	}

Lastly I would be happy to learn of other techniques people use to solve this inconvenients, if you’re willing to share by commenting then go ahead and start enlightening me  πŸ˜‰

Post to Twitter Post to Delicious Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

Tags: , , ,

5 Responses to “ASP.Net State Management And Why You Shouldn’t Use Session Directly”

  1. hkproj says:

    Useful! I never thought about this
    possibility…

  2. RichB says:

    Types stored in
    Session need to be Serializable, otherwise they won’t work in WebFarm scenarios where the session is stored remotely on another machine, or in a database.

    Also, Sessions store the session token
    in a Cookie. This can lead to unexpected XSRF attacks if you’re not careful.

  3. alexmipego says:

    @RichB

    I know those 2 things (very well). I didn’t want to enter into details about security for XSRF attacks but I the solution I talk about makes it easy to convert a project to
    another state management although you can simply disable cookies on ASP.Net config files or use other options.

  4. rektide says:

    I always thought the proper technique was
    to subclass HttpSession for your own app, thereby preventing having to hash-lookup all your values and letting you use clean OO everywhere. I havent done it in ASP.NET, I hope there is a
    way.

  5. Skarllot says:

    Great, I use a solution too much like this.
    For structs I always use
    nullables
    =============================================
    public int? RowsByPage
    {
    get
    {
    object val = pageSession[“PageRows”];
    return
    validateGetStruct(val);
    }
    set { pageSession[“PageRows”] = value; }
    }
    . . .
    private T? validateGetStruct(object val)
    where T : struct
    {
    if (val == null)

    return new T?();
    else if (!(val is T))
    return new T?();
    else
    return new T?((T)val);
    }
    =============================================

Leave a Reply

For spam filtering purposes, please copy the number 3238 to the field below: