Clearing Session variables effectively

Session clearing pattern for ASP.NET applications:

Almost all ASP.NET application use sessions and it is very important to make use of the Session judiciously in order to decrease the burden on IIS server and make the applications performant. Though I agree with reduction in rates of hardware provides the programmers a room to make small mistakes, not the word 'small' but still even these small mistakes can lead to the failure of the application. Hence performance should not be made dependent on the server configuration and developers must try to write the best performant code possible.

 

One of the approaches which I use for taking care of session makes use of the Page controller pattern where all the pages are derived from a common base page as described in the diagram below:

Now the idea to centralize the clearing of unused session variables in base page. Lets dwell into the implemenation a little to understand the pattern better:

1. Zero on a Naming Scheme that will be used for declaring session variables

example:

public const string PAGE_POSTFIX = "PAGE";

public const string SESSION_VARIABLE_1 = "SESSION_VARIABLE_1_" + PAGE_POSTFIX;

public const string SESSION_VARIABLE_2 = "SESSION_VARIABLE_2_" + PAGE_POSTFIX;

public const string SESSION_VARIABLE_3 = "SESSION_VARIABLE_2_" + PAGE_POSTFIX;

2. Write a Helper method that takes a string array of the variables that needs to be preserved and clears all the other session variables that ends with PAGE_POSTFIX.

Code:

#region Session Variables
/// <summary>
/// Clears the removable session keys.
/// </summary>
/// <param name="objectsToPreserve">The objects to preserve.</param>
public static void ClearRemovableSessionKeys(params string[] objectsToPreserve)
{
      string key;
      ICollection sessionKeys;
      List<string> list = new List<string>();

     // Get all the session keys
     sessionKeys = HttpContext.Current.Session.Keys;

     string[] arrSessionkeys = new string[sessionKeys.Count];

    // Session Collection might be modified by some other thread running,
    // hence make a copy of Keys at this instance and work on that Array
    sessionKeys.CopyTo(arrSessionkeys, 0);

    // Remove all the preserveObjects Key from removable list
    if (objectsToPreserve != null)
    {
        for (int i = 0; i < objectsToPreserve.Length; i++)
        {
                 key = objectsToPreserve[i];
                // Work with only those Keys that have PAGE_POSTFIX postfixed to them
                if (key.EndsWith(Constants.C_PAGE))
                {
                        if (Array.IndexOf(objectsToPreserve, key) == -1)
                        {
                              // If the Key does not matches the Key to be excluded then Remove from Session
                              list.Add(key);
                        }
               }
        }
    }
    else
    {
        for (int i = 0; i < arrSessionkeys.Length; i++)
        {
               key = arrSessionkeys[i];
               // Work with only those Keys that have PAGE_POSTFIX postfixed to them
              if (key.EndsWith(Constants.PAGE_POSTFIX))
              {
                  // If the Key does not matches the Key to be excluded then Remove from Session
                  list.Add(key);
              }
        }
     }

     // Remove the removable objects from session
     for (int i = 0; i < list.Count; i++)
     {
          HttpContext.Current.Session.Remove(list[i]);
     }
}
#endregion

3. Declare a Base Page which has a private variable that controls the execution of ClearRemovableSessionKeys method, but default it to true.

Code:

public class MyBase : System.Web.UI.Page
{

     /// <summary>
     /// Initializes a new instance of the <see cref="MyBase"/> class.
     /// </summary>
     public MyBase()
             : base()
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="MyBase"/> class.
    /// </summary>
    public MyBase(bool clearSession)
             : base()
    {
          _clearSession = clearSession;
    }

 

    /// <summary>
    /// control the call to ClearRemovableSession
    /// </summary>
    private bool _clearSession = true;

   ..........

   .......

}

4. Declare a public property on the base page to hold the Session Keys that needs to be preserved and passed on to the Helper.ClearRemovableSessionKeys()

Code:

 

public class MyBase : System.Web.UI.Page
{

........

.......

      /// <summary>
      /// Gets or sets the session keys to preserve.
      /// </summary>
      /// <value>The session keys to preserve.</value>
      public string[] SessionKeysToPreserve
      {
             get { return _sessionKeysToPreserve; }
             set { _sessionKeysToPreserve = value; }
      }

       /// <summary>
       /// array of session keys
       /// </summary>
       private string[] _sessionKeysToPreserve = null;

........

.......

}

 

5. In the Base Page override the OnLoad method and based on the value of _clearSession call ClearRemovableSessionKeys method.

Code:

 

public class MyBase : System.Web.UI.Page
{

........

.......

/// <summary>
/// Raises the <see cref="E:System.Web.UI.Control.Load"></see> event.
/// </summary>
/// <param name="e">The <see cref="T:System.EventArgs"></see> object that contains the event data.</param>
protected override void OnLoad(EventArgs e)
{
         if ((_clearSession) && (!Page.IsPostBack))
         {
                Helper.ClearRemovableSessionKeys(_sessionKeysToPreserve);
         }

        base.OnLoad(e);
}

 

........

.......

}

5. Inherit all the pages from the Base Page, override the OnPreInit() on the Derived Page and set the base page exposed SessionKeysToPreserve property. The SessionKeysToPreserve property should be intialized with session keys that will be utilized in the page being derived and needs to be preserved for the proper functioning of the current page.

Code:

 

public partial class DerivedPage : MyBase
{

/// <summary>
/// Raises the <see cref="E:PreInit"/> event.
/// </summary>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
#region OnPreInit
protected override void OnPreInit(EventArgs e)
{
this.SessionKeysToPreserve = new string[] { SESSION_VARIABLE_1, SESSION_VARIABLE_3 };
base.OnPreInit(e);
}
#endregion

}

That is all and as per the above example whenever any other page apart from DerivedPage is called the SESSION_VARIABLE_1 and SESSION_VARIABLE_3 will be cleared automatically, but in case of DerivedPage only SESSION_VARIABLE_2 will be cleared as SESSION_VARIABLE_1 and SESSION_VARIABLE_3 are intialized as Keys to preserve.

 

I hope this helps, there are many other ways to centralize this and am open for suggestions to improve the same. I would be writing on ways to centralize the Authorization and Validation summary display in next entry.