Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Session Manager Utility for ASP.NET

0.00/5 (No votes)
6 Jul 2014 4  
Session Manager Utility for ASP.NET

Introduction

In my last post, Session in ASP.NET MVC, I explained how to use single session for ASP.NET MVC projects. Single session is obviously the best practice. But sometimes, we many need to use multiple sessions in our project. So, let’s check a utility class for our session management.

Background

The aim would be to make a:

  • Utility class which will be able to fulfill our session based requirements like adding, removing, replacing, retrieving, etc. sessions.
  • Session enlistments, so that we will be able to say at a glance what number of sessions are been used in our project, and using which keys they are been stored.

Using the Code

First, we will try to enlist each individual the session’s keys/names using a enum. This enum will help use in later cores.

internal enum SessionEnum
{
    LogOn,
    Permission,
    LogInName,
    LogInTime
}

Now let's see the SessionManager which manages our sessions.

As you can see, we can make an object of this class by providing the previously discussed SessionEnum or not. And it is important to know.

  • If you want to use the methods declared inside the #region session, you obviously have to provide a SessionEnum, or an error would be shown. Because they work for a particular session key only.

Rest of the methods work with some basic session management requirements like (see the public/internal methods):

internal class SessionManager
{
    private readonly HttpSessionState _session;
    private readonly SessionEnum? _sessionKey;
    private string SessionName
    {
        get
        {
            if (_sessionKey == null)
            {
                throw new NullReferenceException("No sessionKey provided at the constructor");
            }
            return _sessionKey.ToString();
        }
    }

    internal SessionManager()
    {
        _session = HttpContext.Current.Session;
    }

    internal SessionManager(SessionEnum sessionKey) : this()
    {
        _sessionKey = sessionKey;
    }

    #region Depends on SessionKey provided using constructor
    internal bool DoesKeyExist()
    {
        if (!HasAnySessions())
        {
            return false;
        }
        bool exist = false;
        for (int i = 0; i < _session.Count; i++)
        {
            exist = _session.Keys[i] == SessionName;
            if (exist)
            {
                break;
            }
        }
        return exist;
    }

    internal bool IsNull()
    {
        return _session[SessionName] == null;
    }

    internal void SetNull()
    {
        _session[SessionName] = null;
    }

    internal TSource Get<TSource>()
    {
        return (TSource) _session[SessionName];
    }

    internal void Add<TSource>(TSource model)
    {
        _session.Add(SessionName, model);
    }

    internal void Replace<TSource>(TSource model)
    {
        _session[SessionName] = model;
    }

    internal void Remove()
    {
        _session.Remove(SessionName);
    }
    #endregion


    internal string GetSessionId()
    {
        return _session.SessionID;
    }

    internal bool HasAnySessions()
    {
        return _session.Count > 0;
    }

    internal void RemoveAll()
    {
        _session.RemoveAll();
    }

    internal void AbandonSessions()
    {
        _session.Abandon();
    }
}

Some of the uses:

/*Adding sessions*/
new SessionManager(SessionEnum.LogOn).Add(new UserSessionModel()
    {LogInName = "scott", LogInTime = DateTime.Now});
new SessionManager(SessionEnum.LogInName).Add("scott");
new SessionManager(SessionEnum.LogInTime).Add(DateTime.Now);

/*Session id*/
string sessionId = new SessionManager().GetSessionId();

/*HasAnySessions*/
bool hasSession = new SessionManager().HasAnySessions();

/*DoesKeyExist*/
bool hasLogOnKey = new SessionManager(SessionEnum.LogOn).DoesKeyExist();            //true
bool hasPermissionKey = new SessionManager(SessionEnum.Permission).DoesKeyExist();  //false as 
                                                                                 //it is not added yet

/*IsNull*/
bool isLogOnSessionNull = new SessionManager(SessionEnum.LogOn).IsNull();           //false
bool isPermissionSessionNull = new SessionManager(SessionEnum.Permission).IsNull(); //true as 
                                                                                //it is not added yet

/*Replace*/
new SessionManager(SessionEnum.LogOn).Replace(new UserSessionModel() 
    { LogInName = "scottRocks", LogInTime = DateTime.Now.AddDays(-2) });

/*Get*/
var user = new SessionManager(SessionEnum.LogOn).Get<UserSessionModel>();   //success

/*Remove*/
new SessionManager(SessionEnum.LogOn).Remove();
user = new SessionManager(SessionEnum.LogOn).Get<UserSessionModel>();       //null


var manager = new SessionManager();

/*Remove All*/
manager.RemoveAll();
hasSession = new SessionManager().HasAnySessions();

/*Abandon Session*/
manager.AbandonSessions();
hasSession = new SessionManager().HasAnySessions();

Make the Flexibility Little Tighter

Our above class works fine. But if you want to add some restrictions, which are important if you are working with multiple session objects in project:

  1. Avoid using a key to be added, more than once.
  2. Get a session means, it needs to be present till now with specifying type. Being null is not acceptable.
  3. Remove a session means, being null is not acceptable.
  4. If a session with a specific type of object using specific key is once created, it can only hold that type of object for life cycle.

This means you know exactly what is going on with the sessions, and it's going on as we wanted it to be.

To do so, re-edit the utility class by replacing some of the methods from above, which may look like mine:

internal TSource Get<TSource>()
{
	if (IsNull())
	{
		throw new Exception(String.Format("The session with key '{0}' is null", SessionName));
	}
	return (TSource) _session[SessionName];
}

internal void Add<TSource>(TSource model)
{
	if (DoesKeyExist())
	{
		throw new Exception(String.Format("The session key '{0}' is already been used, 
                            try using another key",
			SessionName));
	}
	_session.Add(SessionName, model);
}

internal void Replace<TSource>(TSource model)
{
	if (!DoesKeyExist())
	{
		throw new Exception(String.Format("The session key '{0}' is not been used yet", SessionName));
	}

	if (!IsNull() && (model.GetType() != _session[SessionName].GetType()))
	{
		throw new Exception(
			String.Format("The old data type of session key '{0}' 
                           is not matching with the new data type",
				SessionName));
	}
	_session[SessionName] = model;
}

internal void Remove()
{
	if (!DoesKeyExist())
	{
		throw new Exception(
			String.Format("The session with the key '{0}' is already been removed, 
                           or not used yet", SessionName));
	}
	_session.Remove(SessionName);
}

Limitations

  1. I have tested the code on ASP.NET web forms, web service, and MVC.
  2. If you want user session model need to be more typed, try to avoid Base-child relational models on the replace method because the comparison may vary at some points:
    model.GetType() != _session[SessionName].GetType()
  3. Try to use it inside the First Server Communication Layer only, rather than at logic or data layers.

Find the Visual Studio 2010 project solution in the attachment.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here