Singleton Patterns for ASP.NET

3

June 1, 2011 by Alistair Deneys

Update 13th June 2011: Thanks to Damian Kulik who left a comment on this post pointing out that the classic singleton pattern I show below is not thread safe and provided a link to a great article showing a few options for creating a thread safe singleton in C#. I’ve updated the code examples for the classic singleton pattern to use a thread safe singleton pattern.

Many of you are probably aware of the Singleton pattern. This code pattern allows creating a single instance of an object and ensure there is only ever one instance of it as well as providing centralised access to the single instance. This pattern is useful in many cases such as loading expensive data from a data store into memory and caching it, or tracking state inside an application.

The problem I sometimes see people having with this pattern is to do with the lifetime of an ASP.NET application.

Classic Singleton Pattern

First of all, the classic singleton pattern. This pattern ensures you only have a single instance of your object and provide a global mechanism to retrieve the object.

Original non-thread-safe singleton pattern

namespace Demo
{
    public class Singleton
    {
        private static Singleton m_instance = null;

        public static Singleton Instance
        {
            get
            {
                if (m_instance == null)
                    m_instance = new Singleton();

                return m_instance;
            }
        }

        private Singleton()
        {
        }
    }
}

Thread-safe singleton

namespace Demo
{
    public sealed class SafeSingleton
    {
        private static readonly SafeSingleton m_instance = null;

        public static SafeSingleton Instance
        {
            get
            {
                return m_instance;
            }
        }

        static SafeSingleton()
        {
            m_instance = new SafeSingleton();
        }

        private SafeSingleton()
        {
        }
    }
}

Note how the constructor is private? That means only this class can create instance of this class, which is done through the static Instance property.

This pattern is good when you have data which transcends a request or session and really should be tied to the application. Something like a settings object which only needs to read the settings once and can then cache the data.

In a Sitecore project, if you were to create a settings object which read it’s data from the Sitecore context database then you’d also need to include a way to refresh the data upon publish in case the items you’ve read the settings from have changed.

To achieve this all you need to do is separate the reading of the settings into a method and subscribe to the publish:end event and reread the settings.

Original non-thread-safe settings singleton

using System;
using Sitecore;

namespace Demo
{
    public class Settings
    {
        private static Settings m_instance = null;

        public int PostCount
        {
            get;
            protected set;
        }

        public static Settings Instance
        {
            get
            {
                if (m_instance == null)
                    m_instance = new Settings();

                return m_instance;
            }
        }

        private Settings()
        {
            Load(this, new EventArgs());
            Sitecore.Events.Event.Subscribe("publish:end", new EventHandler(Load));
        }

        protected void Load(object sender, EventArgs args)
        {
            var settings = Context.Database.GetItem("/sitecore/content/settings");
            PostCount = int.Parse(settings["post count"]);
        }
    }
}

Thread-safe settings singleton

using System;
using Sitecore;

namespace Demo
{
    public sealed class SafeSettings
    {
        private static readonly SafeSettings m_instance = null;

        public int PostCount
        {
            get;
            private set;
        }

        public static SafeSettings Instance
        {
            get
            {
                return m_instance;
            }
        }

        static SafeSettings()
        {
            m_instance = new SafeSettings();
        }
        
        private SafeSettings()
        {
            Load(this, new EventArgs());
            Sitecore.Events.Event.Subscribe("publish:end", new EventHandler(Load));
        }

        private void Load(object sender, EventArgs args)
        {
            var settings = Context.Database.GetItem("/sitecore/content/settings");
            PostCount = int.Parse(settings["post count"]);
        }
    }
}

Singleton per Request Pattern

The issue with the classic singleton pattern for most ASP.NET developers is to do with the lifetime of an ASP.NET application. A classic singleton pattern stores the reference to the singleton object in a static variable. This static variable will exist as long as the application which contains it does. And in ASP.NET the application lives in the application pool. A new application doesn’t get created for each request as many developers might expect. The application lives for a duration much longer than a single request. So if you create a singleton it is the same object cross request and cross session.

Recently I stumbled upon a very nice solution to this issue. The singleton per request pattern. This is a variation on the classic singleton pattern. The singleton instance instead of being stored in a static variable is stored in the HttpContext’s Items property. This means the singleton will only live as long as the current request because we get a new HttpContext object for every request.

using System.Web;

namespace Demo
{
    public class RequestSingleton
    {
        private const string KEY = "RequestSingleton";

        public static RequestSingleton Instance
        {
            get
            {
                if (HttpContext.Current.Items[KEY] == null)
                    HttpContext.Current.Items[KEY] = new RequestSingleton();

                return HttpContext.Current.Items[KEY] as RequestSingleton;
            }
        }

        private RequestSingleton()
        {
        }
    }
}

This pattern is good when we have data we want to store that is only relevant for the current request. For example, in a Sitecore instance we might detect certain conditions in the request begin pipeline that we need to persist for a control (or rules engine component) later in the request.

Singleton per Session Pattern

This pattern is a slight variation on the above Singleton per Request pattern. In this pattern I want my singleton object to be tied to the session so it lasts for multiple requests, but only for the current user.

All I need to do to the above pattern is store my singleton object in session rather than the HttpContext Items property.

using System.Web;

namespace Demo
{
    public class SessionSingleton
    {
        private const string KEY = "SessionSingleton";

        public static SessionSingleton Instance
        {
            get
            {
                if (HttpContext.Current.Session[KEY] == null)
                    HttpContext.Current.Session[KEY] = new SessionSingleton();

                return HttpContext.Current.Session[KEY] as SessionSingleton;
            }
        }

        private SessionSingleton()
        {
        }
    }
}

This pattern is good when I have user specific data I need to store in the singleton such as what their quicklinks are or what theme colour they chose.

Access to Global Objects

So what benefit does the Singleton per Request and Singleton per Session patterns carry over just accessing the global objects directly? In this case the global objects I’m referring to is the HttpContext Items object and the Session object. They are global cause we can gain access to them from anywhere in our application through HttpContext.Current.Items and HttpContext.Current.Session.

This issue with global objects is it’s very difficult to determine what is changing the object. The singleton patterns shown here centralise access to the singleton object. There is only a single way to get that object and access it’s members. This is much safer and leads to more easily maintainable code.

Another benefit this pattern holds over direct access to the global objects is strongly typed access to the data. Both the Items and Session objects are a string-object dictionary. Every time you get an object out of those objects you need to cast it to the proper type. But having centralised access to the data we can simply provide strongly typed access to the data, only needing to provide the casting in a single location.

Advertisements

3 thoughts on “Singleton Patterns for ASP.NET

  1. Hello Alistair,

    Very informative article, however the construction of Singleton you have used here is not a thread-safe. I used to implement singletons in the same way, however my colleague pointed out that it is not secure you a single instance per application domain.

    I experienced that kind of issue in my Scripts Optimiser (combine and minify assets), which is a heavily used functionality and has to deal with multiple requests constantly. Therefore I would strongly recommend reading an article below

    http://csharpindepth.com/Articles/General/Singleton.aspx

    in which author concludes how to build a thread-safe singleton. In 99% of situations a standard example is good enough though.

    I am subscribed to your blog around 8 months now and I found it very helpful, please continue a good work:)

    Regards,
    Damian Kulik

  2. Alistair Deneys says:

    Thanks for the tip Damian. I’d never really thought about how thread safe that pattern was, probably cause I’ve been using that version of the pattern for such a long time.

    I’ve updated my post to include thread-safe versions of the coe examples where appropriate.

  3. HttpContext.Current.Session vs HttpContext.Current.Cache ? performance tips about it ?

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

Categories

The views expressed on this blog are solely my own and do not necessarily reflect the views of my employer.
%d bloggers like this: