8.26.2012

Customizing your application resources

Picture this: You have an asp.net application in which you support multiple languages through the use of resources (global and local resources) and depend on the .NET framework to do all the hard work of loading the correct resources depending on the current UI culture. All is well until you have a requirement of customizing a handful of resources (either per user, per customer, or any other criteria you may think of).
Anyone who has enough knowledge of the .NET framework, tells you right away that you can create your own resource provider and take control of all the aforementioned mechanism. You can find several articles online, including MSDN articles with a detailed explanation of how to provide your own resource provider (here's an interesting article about it).
There are several online resources supplying examples of resource providers that load resources from the database and other similar approaches. However in this specific situation we would like to preserve the default provider behaviour and override only when the target resource has been customized. It seems pretty easy, right? We override the default provider, find if the target resource has been customized, if so, return the new value, otherwise, call the base class implementation, right?
Wrong! You can't extend it because the GlobalResXResourceProvider class (default provider responsible for resolving global resources) is internal, the LocalResXResourceProvider class (default provider responsible for resolving local resources) is internal and the ResXResourceProviderFactory class (provider factory responsible for creating instances of the global and local resource providers) is... guess what... internal! So, it seems Microsoft did not want us to extend this classes...
Right now we could opt to rewrite this providers ourselves OR we could avoid that hard work and opt to create our resource providers as proxies/surrogates (see the design pattern here) that end up invoking the default providers. The only question is how do we initialize these default providers if they are internal... It's not pretty, but I can only think of reflection. In this case, instead of accessing both default providers through reflection I chose to minimize the points of failure by creating only the default resource provider factory through reflection and calling it's public interface to retrieve the default provider instances.
So here's the how our brand new resource provider factory looks like:

Plain simple, just create our brand new customizable resource providers and pass them a "fallback" provider, which will be used to resolve any resource that hasn't been customized. Our new resource providers just have to determine if they should resolve the resource or if they should use the "fallback" provider (which will be the default provider). Something like this:


Nice and easy! Accessing internal stuff in the framework is obviously something to be avoided, but I think we're pretty safe here. Resource providers have been around for a while and I don't expect Microsoft to remove this class sooner.

Sem comentários: