Home > Programming > Strongly typed ASP.NET session

Strongly typed ASP.NET session

Following my previous post on strongly typed dictionaries, I wanted to use the same DictionaryAdapter component for ASP.NET sessions. However, the ASP.NET session object does not implement IDictionary. Since the session object acts like a dictionary, we’ll need to wrap it. Using the session adapter found here, we can now utilize the DictionaryAdapter component to create strongly typed implementations.

DictionaryAdapterFactory factory = new DictionaryAdapterFactory();
IHomeSession session = factory.GetAdapter<IHomeSession>(new SessionDictionary(HttpContext.Current.Session));

Each of my controllers only use a subset of the information stored in session. To avoid creating a “master” interface that contains all the different keys, I can create multiple interfaces that only map values that the controller needs.

public interface IHomeSession
{
	string First { get; set; }
	string Last { get; set; }
	int? Age { get; set; }
}

public interface IAccountSession
{
	string First { get; set; }
	string Last { get; set; }
	string Middle { get; set; }
	int? Age { get; set; }
}

public interface IOtherSession
{
	[Key("OtherFirstName")]
	string First { get; set; }

	[Key("OtherLastName")]
	string Last { get; set; }
}

Each of these interfaces are injected into different controllers. The Home controller would be injected with IHomeSession and so forth. Since the DictionaryAdapter component maps the property name to keys, the First string property on IHomeSession would map to the same value as the First string property on IAccountSession. Although IOtherSession also has a First string property, I’m using the Key attribute to denote that it should map to the key OtherFirstName.

public class HomeController : Controller
{
	private readonly IHomeSession session;

	public HomeController(IHomeSession session)
	{
		this.session = session;
	}

	public ActionResult Index(string first, string last, int age)
	{
		this.session.First = first;
		this.session.Last = last;
		this.session.Age = age;

		return View();
	}
}

I can register each interface separately:

container.Register
(
    Component
        .For<IHomeSession>()
        .UsingFactoryMethod(x =>
        {
            DictionaryAdapterFactory factory = new DictionaryAdapterFactory();
            return factory.GetAdapter<IHomeSession>(new SessionDictionary(HttpContext.Current.Session));
        })
);

… but this quickly becomes a friction point if we have multiple interfaces and would like to create additional interfaces in the future. Instead, we can register the DictionaryAdapterFactory as a singleton and get a list of all the interfaces that match a certain convention. We’ll loop through and register each one individually.

container.Register
    (
        Component
            .For<DictionaryAdapterFactory>()
            .LifeStyle.Singleton
    );

IEnumerable<Type> sessions = 
	Assembly
		.GetExecutingAssembly()
		.GetTypes()
		.Where(x => x.IsInterface && x.Name.EndsWith("Session"));

foreach (Type session in sessions)
{
    Type sessionTemp = session;

    container.Register
        (
            Component
                .For(session)
                .UsingFactoryMethod(x =>
                    {
                        DictionaryAdapterFactory factory = x.Resolve<DictionaryAdapterFactory>();
                        return factory.GetAdapter<object>(sessionTemp, new SessionDictionary(HttpContext.Current.Session));
                    })
                .LifeStyle.PerWebRequest
        );
}

At this point, we can create additional interfaces that match the current convention and the container will automatically register and inject them.

  1. March 12, 2011 at 11:10 am

    Thanks for the link to my session dictionary adapter! I like the idea of using different separate interfaces on a per controller basis. One suggestion for an alternate way to register all of the session adapters by convention would be to have an empty ISession (or IHttpSession) interface that each of your session objects would implement. Then you just register any type that implements that interface, and you don’t need to follow a certain naming convention.

  1. February 7, 2012 at 1:07 am
  2. October 20, 2012 at 11:27 pm

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: