I'm trying to build a localization-aware class library under .NET. This class library is designed to be usable by both regular "fat client" Windows applications, and by ASP.NET serverside web apps.
Localisation - in this particular case, it means using custom strings for each language - requires that I create a 'ResourceManager' object which will fetch culture-specific resources from the appropriate satellite assembly. So if I'm trying to run in Chinese, I'll use a ResourceManager that has been created to point at the assembly containing all my Chinese resources. If I'm running in Spanish, I'll use a ResourceManager that has been created to point at the assembly containing all my Spanish resources. Etcetera.
It doesn't seem terribly efficient to re-create the resource manager every single time I want to pull out a string, and then immediately throw it away again. It would be much nicer to keep it around between uses and then throw it away only when I don't need it anymore.
I could just use a singleton or global variable, but this breaks when I'm working in an environment where different threads run under different cultures - like, say, ASP.NET. Under ASP.NET, each request is run in a different thread, and so I may have one Chinese and one Spanish user making requests at the same time. Ho hum.
As such it becomes clear that each thread is going to need its own pointer to a ResourceManager. They don't each need their own ResourceManagers - the ResourceManager for a particular culture can be shared across all threads running under the same culture - but they do need independent pointers. Sounds like a good time to use Thread Local Storage, or TLS for short - a chunk of memory specific to each thread. I can store my pointer in there. Under a single-threaded application, a TLS variable is just the same as a global variable.
So, here's what I think I'm going to do. Because I'd like to re-use this approach for other libraries, and each library is going to have its own satellite assemblies that will need ResourceManagers, I'm going to have my libraries create a dictionary in TLS, and this dictionary will contain library/resourcemanager pairs. Under a singlethreaded fat client model that only uses one library, this will only ever contain one entry. Minor waste of space, but oh well. Under ASP.NET with all my libraries, each thread will contain a dictionary with different values.
There's just one complication. To avoid the overhead involved in creating and deleting threads, IIS uses a technique known as 'thread pooling' - it creates a bunch of threads when it starts up, and then they all go to sleep. When a request comes in, IIS wakes a thread up, it handles the request, and then it goes back to sleep again. The net effect is that threads are very rarely created and deleted.
This is where the dictionary aspect of things comes in handy. Because I've grouped all the ResourceManagers together into single collection objects, I can chunk away any managers that have been registered in BeginRequest. Or, even better, I can save them out into the session data in EndRequest and then bring them back again in BeginRequest.
I think it works. I'm on an XP Home machine at the moment - no IIS - so I can't really test it, but I'll try writing my own little thread pooling system and continually rotating the locales to see what happens.