For logging purposes of an ASP.NET web application, I keep some state information in a static class. These fields are marked [ThreadStatic]
so every thread has its own copy of the field. The logging methods are called from the HttpApplication event methods:
- Application_BeginRequest (request start, initialise state)
- Application_AcquireRequestState (session and user are known)
- Application_EndRequest (request end, clean up)
I can now observe that, under certain circumstances, a page request is processed in different threads. The BeginRequest event runs on thread 18 while the following events run on thread 4. Of course my thread-static data is then not available and an error occurs.
Most of the time this works just fine and every request is processed in a single thread only. But when I request a page that loads ~5 seconds and after 1-2 seconds click on another link, both requests run in parallel. The first is completed on thread 24 (where it was also started) after 5 seconds, while the other starts on thread 18, but after the first request has completed, the second continues to run on thread 4.
Trying it with 3 overlapping long requests, it's a pure chaos. I can even watch two requests starting on the same thread while they later continue on different threads each. There doesn't seem to be any relationship between a request and a thread.
How can it be that a request is changing threads? It's losing all of its state if it decides to move on to another thread. And every description I can find says that it all happens in a single thread.
ASP.NET 4.0 on IIS 7, Windows Server 2008 R2, x64.
Alternative: If I cannot rely on requests being processed in only a single thread from the start to the end, then what would be the best location to store small amounts of per-request data (currently an integer and a class) that is very fast accessibly? And preferably also works without a reference to System.Web (my code is targeting the client profile as well). I know about HttpContext.Current.Items[key]
but it's looked up somewhere deep in the remoting assembly and involves a dictionary which seems a lot slower than a thread-static field.