OperationContext is ThreadStatic

WCF Services tend to be big, heavy duty things. When I write a service I often want it to do a lot of work for a lot of clients, and it should do it efficiently. This usually means that I will use multithreaded code to get things done concurrently. Whether using the ThreadPool or instantiating a thread of my own, I expect this is a common scenario for WCF service writers.

That’s why I was suprised today to find out that the OperationContext of the current service call, our entry point for getting context information about the current call, its headers and so forth – is marked as [ThreadStatic]. This means that the moment I fork off to another thread, I lose all context information. If I want it available, I have to do it myself.

I don’t know how ASP.NET deals with this problem. If I spin a new thread under ASP.NET, I don’t lose my current HttpContext. A quick glance with Reflector shows that there’s no [ThreadStatic] anywhere. Whatever features of IIS they use there, it’s probably unavailable for WCF, so we have to do it manually.

The simplest way to pass the context to a thread is just to send it as a parameter:

void Method ()
{
    ThreadPool.QueueUserWorkItem(ThreadMethod, OperationContext.Current);
}

void ThreadMethod(object state)
{
    OperationContext.Current = state as OperationContext;
    // Do whatever.
}

Side note: Note the automatic delegate inference that .NET 2.0 does, rather than forcing me to manually create a WaitCallback delegate:
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadMethod), OperationContext.Current);
I don’t think this was possible in v1.1.

If we want to spin a thread of our own, we can use the ParameterizedThreadStart delegate:

void Method ()
{
    Thread t = new Thread(new ParameterizedThreadStart(ThreadMethod), OperationContext.Current);
    t.Start();
}

If we have parameters to pass to our method, though, we need to be even hackier – maybe define a struct or class to hold our OperationContext as well as the custom parameters, and pass that on to the ThreadMethod and have it disassemble it.

There is a better way to build a Thread Launcher than can pass the ObjectContext. I’ll elaborate on that in my next post.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.