Thread Singleton

There are a couple of classes in most projects that end up being singletons. The two most adept for this paradigm are Configuration and Database Handle Pooling. Both get used by many objects, both should only be instantiated once for efficiency and data integrity and we don't want to have to pass either of them around all the time. Voila, perfect candidate for singleton's.

When i started working with ASP.NET, however I ran into a problem with this, since ASP.NET persists over many requests and is multithreaded. For configuration that's user specific, that could be a problem. For transactional Database handles it's definitely a problem. Simplest way is to put it into the HttpContext.Current.Items collection. But now your code is tied to ASP.NET. You could write wrappers that test the environment and wrap the objects in singleton or HttpContext as appropriate, but that still leaves the singleton being shared across threads, should you write other multi-threaded apps.

I finally found a solution (sorry, i can't give credit because it's been a while and I can't find the original article) to this in the form of a Thread Singleton. This pattern uses the System.Runtime.Remoting.Messaging.CallContext to store our singleton. I've used it so many times now, that i figured i'd better write it down here so i don't have to dig through old code every time i want to re-use it:

using System;
using System.Runtime.Remoting.Messaging;

namespace Claassen.Util
{
    public class ThreadSingleton
    {
        /// <summary>
        /// Some unique string that identifies this class.. I just use the
        /// Namespace qualified name
        /// </summary>
        const string SINGLETON_ID = "Claassen.Util.ThreadSingleton";

        /// <summary>
        /// Accessor/Factory for the ThreadSingleton
        /// </summary>
        private static ThreadSingleton Current
        {
            get
            {
                // pull the object from the CallContext
                ThreadSingleton threadSingleton = (ThreadSingleton)CallContext.GetData(SINGLETON_ID);
                if( threadSingleton == null )
                {
                    // if there was nothing in the CallContext, create and add it
                    threadSingleton = new ThreadSingleton();
                    CallContext.SetData(SINGLETON_ID,threadSingleton);
                }
                return threadSingleton;
            }
        }

        // Class code would follow
    }
}