I need to instantiate a singleton object per web request, so that the data is processed once and is valid throughout the request, I was using HttpContext.Current.Items
to share data during HTTP request, everything was fine until we needed the singleton object instance across multiple threads, the first thing that I came up with was to pass the HttpContext instance to the new thread:
HttpContext context = HttpContext.Current;
ThreadPool.QueueUserWorkItem(callback =>
{
HttpContext.Current = context;
// blah blah
});
Which I don't think is a thread-safe approach as noted here.
Using Reflector I figured HttpContext.Current.Items actually uses CallContext to store objects in each logical thread. So I changed the singleton interface to this:
public static SingletonType SingletonInstance
{
get { return CallContext.GetData(key) as SingletonType; }
set { CallContext.SetData(key, value); }
}
And simply overwrite SingletonInstance
when starting any new thread! The code works fine, however it seems that somehow under heavy load, CallContext.GetData(key) returns null and the application crashes with with a null reference exception!
I was thinking, if CallContext.GetData
is atomic? But it just doesn't seem right, the CallContext is thread specific data storage and must be atomic or I am missing the point!
My other guess is that setting the SingletonInstance (CallContext.SetData) happens in one thread while CallContext.GetData executes in another as noted here but I don't know how/why?
update:
We are keeping an instance of each online user in an array on the server. The singleton object is actually a reference to the object representing current user. Current user must be unique and available in each thread for database querying, logging, error handling and more, this is how it is done:
public static ApplicationUser CurrentUser
{
get { return CallContext.GetData("ApplicationUser") as ApplicationUser ; }
set { CallContext.SetData("ApplicationUser", value); }
}