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.
- 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. - 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. - 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. - 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… - 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ΓΒ π
Tags: application, ASP.Net, session, state management
Useful! I never thought about this
possibility…
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.
@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.
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.
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);
}
=============================================