Today's lesson learned: the [ThreadStatic] attribute is only useful when YOU control the ThreadPool (and the lifecycle of the threads). It also reminds one to think about variable scope/lifetime especially in the context of ASP.NET.
An interesting day and I ran into some code that made interesting (and arguably not necessary use of a static member variable). More and more I feel that static member variables (whether hidden by a property accessor) will bite you in the ass unless they were really meant to be readonly (WORM - write once read many) variables.
Two interesting things:
1. I noticed this behavior and saw that the fantastically smart Chris Brumme had good things to say about on DevelopMentor's DOTNET List. It's kind of a DUH moment when you realize it of course it should work that way. Definitely don't count on the constructors of static fields marked with ThreadStatic.
2. Don't slap a [ThreadStatic] attribute on a static member when you're operating within ASP.NET as chances are you don't control the thread life...you inherit a worker thread. ThreadStatic gives you thread local storage, not HttpContext local storage! If you need to store something away to be used later in the same HTTP request, think about my favorite ASP.NET class, the little-known and not-used-enough System.Web.HttpContext.Current.Items (aside: great article by Susan Warren on Context). In ASP.NET your code is run on a WorkerThread from the 25 or so threads in the default ASP.NET worker thread pool and the variable that you think is "personal private to your thread" is personal private...to you and every other request that this worker thread has been with. Under load you may well find your variable modified.
To sum up places to stash things in ASP.NET:
||A key/value pair collection of values that is accessible by every user of the application. |
||The ASP.NET Cache object, which provides programmatic access to the cache. Arguably a fancier face on Application.|
||A key-value pair collection that you can use to pass information between all of the components that participate in the processing of a single HTTP request. This is a great place to put things that need to be shared between ASP.NET pages and components farther downstream that will inherit the current HttpContext.|
||A key/value pair collection of values that are accessible by a single user of the application (When using InProc Session in ASP.NET 1.0 Session is really just a pretty indexed-by-cookie-guid face on the Cache object!)|
When using ASP.NET think twice, then think again, before throwing that static (or Shared) keyword in there. Perhaps there is a scope better suited for what you're trying to do.