HTTPContext over streams

I need to instantiate a singleton object for each web request so that the data is processed once and is valid for the whole request, I used HttpContext.Current.Items

to exchange data during the HTTP request, it was ok until we needed a singleton object instance for multiple streams, the first thing I came up with is to pass the HttpContext instance to a new stream:

HttpContext context = HttpContext.Current;
ThreadPool.QueueUserWorkItem(callback =>
    {
        HttpContext.Current = context;
        // blah blah
    });

      

I don't think this is the thread-safe approach noted here .

Using Reflector I figured out HttpContext.Current.Items actually uses CallContext to store objects in each logical thread. So I changed the singleton interface:

public static SingletonType SingletonInstance
{
    get { return CallContext.GetData(key) as SingletonType; }
    set { CallContext.SetData(key, value); }
}

      

And just 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 a null exception!

I thought if CallContext.GetData

is atomic? But that just doesn't feel right, CallContext is a thread dependent data store and must be atomic or I'm missing the point!

My other guess is that the SingletonInstance (CallContext.SetData) setting happens on one thread and the CallContext.GetData is done on another, as noted here , but I don't know how / why?

update:

We store an instance of each online user in an array on the server. The singleton object is actually a reference to an object representing the current user. The current user must be unique and available on each thread for database queries, logging, error handling, etc., this is how it is done:

public static ApplicationUser CurrentUser
{
    get { return CallContext.GetData("ApplicationUser") as ApplicationUser ; }
    set { CallContext.SetData("ApplicationUser", value); }
}

      

+3


source to share


3 answers


ASP.NET can carry a request between threads if it is under load. After receiving the request, the page designer can execute one thread and load the page on another. On this thread, the CallContext and ThreadStatic switch are not portable, but luckily the HttpContext.

This can be misleading since HttpContext is the calling context, but this is a bit quirky in ASP.NET, perhaps due to the reduction in corners to improve performance.



You will need to remove the dependencies for the CallContext and use the entire HttpContext path.

You can read more about this in the awesome blog post from Piers7.

+3


source


This was resolved during the chat session.



These are essentially time-consuming tasks, and the decision to use an external service (Web or regular Windows service) was chosen as the best solution to the problem.

+1


source


Optimizing your second method is the best approach. This is the thread safe version of your singleton:

public sealed class SingletonType
{
    #region thread-safe singletone

    private static object _lock = new object();
    private SingletonType() { }

    public static SingletonType SingletonInstance
    {
        get
        {
            if (CallContext.GetData(key) == null)
            {
                lock (_lock)
                {
                    if (CallContext.GetData(key) == null)
                        CallContext.SetData(key, new SingletonType());
                }
            }

            return CallContext.GetData(key) as SingletonType;
        }
    }

    #endregion

    //
    //
    // SingletoneType members
    //
    //
}

      

NOTE: using block lock { }

is key.

0


source







All Articles