Introduction

Just about every ASP.NET application needs to keep track of data for a user's session. ASP.NET provides the HttpSessionState class to store session-state values. An instance of the HttpSessionState class for each HTTP request is accessible throughout your application using the static HttpContext.Current.Session property. Access to the same instance is made simpler on every Page and UserControl using the Session property of the Page or UserControl.

The HttpSessionState class provides a collection of key/value pairs, where the keys are of type String and the values are of type Object. This means that Session is extremely flexible and you can store just about any type of data in Session.

But (there is always a but) this flexibility does not come without a cost. The cost is the ease with which bugs can be introduced into your application. Many of the bugs that can be introduced will not be found by unit testing, and probably not by any form of structured testing. These bugs often only surface when the application has been deployed to the production environment. When they do surface it is often very difficult, if not impossible, to determine how they occurred and be able to reproduce the bug. This means they are very expensive to fix.

This article presents a strategy to help prevent this type of bug. It uses a Design Pattern called a Facade, in that it wraps the very free interface provided by the HttpSessionState class (that can meet the requirements of any application) with a well designed and controlled interface that is the purpose built for a specific application. If you are not familiar with Design Patterns or the Facade pattern, a quick internet search of "facade design pattern" will provide you with plenty of background. However, you do not have to understand design patterns in order to understand this article.

The example code shown in this article is written in C#, but the concepts are applicable to any .NET language.

What is the Problem?

In this section of the article, I will describe the problems with direct access to the HttpSessionState class, without the facade. I will describe the kinds of bugs that can be introduced.

The following shows the typical code written to access session-state variables.

However, when constants are defined locally (e.g. at page level), we might still re-use the same key unintentionally.

A Better Quick Fix

Rather than define constants on each page, group all session key constants into a single location and provide documentation that will appear in Intellisense. The documentation should clearly indicate what the session variable is used for. For example, define a class just for the session keys:

When you need a new session variable, if you choose a name that has already been used you will know this when you add the constant to the SessionKeys class. You can see how it is currently being used and can determine if you should be using a different key.

However, we are still not ensuring consistency of data type.

A Much Better Way - Using a Facade

Only access the HttpSessionState from within one single static class in your application - the facade. There must be no direct access to the Session property from within code on pages or controls, and no direct access to HttpContext.Current.Session other than from within the facade.

All session variables will be exposed as properties of the facade class.

This has the same advantages as using a single class for all the session keys, plus the following advantages:

Strong typing of what gets put into session variables.

No need for casting in code where session variables are used.

All the benefits of property setters to validate what gets put into session variables (more than just type).

All the benefits of property getters when accessing session variables. For example, initialising a variable the first time it is accessed.

An Example Session Facade Class

Here is an example class to implement the Session facade for an application called MyApplication.

The class demonstrates the use of property getters that can provide default values if a value has not been explicitly stored. For example, the StartDate property provides DateTime.MinValue as a default.

The property getter for the UserAuthorisation property provides a simple cache of the UserAuthorisation class instance, ensuring that the instance in the session variables is kept up to date. This property also shows the use of a private setter, so that the value in the session variable can only be set under the control of facade class.

The Username property demonstrates a value that may once have been stored as a session variable but is no longer stored this way.

The following code shows how a session variable can be accessed through the facade. Note that there is no need to do any casting in this code.

Additional Benefits

An additional benefit of the facade design pattern is that it hides the internal implementation from the rest of the application. Perhaps in the future you may decide to use another mechanism of implementing session-state, other than the built-in ASP.NET HttpSessionState class. You only need to change the internals of the facade - you do not need to change anything else in the rest of the application.

Summary

The use of a facade for HttpSessionState provides a much more robust way to access session variables. This is a very simple technique to implement, but with great benefit.

Comments and Discussions

Hi, this is a good article. However, what about uniqueness of the session keys? For example if i have a user control that uses session variables, and I place it on different pages, then the variables would all be cross accessed. Any solutions? I've tried using combination of this.UniqueID + variablename, but if the user control instances placed on different pages happen to have same IDs, then it's no use! Any solutions?

I don't know the data you are putting into session for these user control's, but depending on what it is, it may be appropriate to use View State for these rather than Session State. Usually for data that is related to a particular instance of a control, rather than to the user's session as a whole, it is more appropriate to use View State for the control.

But this is not always the case.

The issue you describe is also an issue if you have an application where you want to allow the user to open two windows that both display the same pages but for different data and rely on unique values in session variables. This needs to be done under control of the application rather than just having the user open a new browser window that is tied to the same ASP.NET session (e.g. File --> New --> Window menu in IE).

What I do in these circumstances is have a unique window instance key for each window. This is stored in a hidden field or view state for the page. When the user requests to open another window through the application, a new window instance key is generarate for each window. Then I change the properties in my session facade class to be a Dictionary of the underlying type, keyed by the window instance key.

You could use this same approach for different instances of your user control.

I had the same problems as described by Rizzy: a Session variable in a UserControl that is to be used in multiple places on a single page. This causes each instance of the User Control to access the same Session variable.

Using the ViewState instead of the Session object seems to have solved this issue.