Problem: an ASP.NET website is connected to a CMS which permits users to modify .resx files.
Modifying .resx resource files during runtime has the unfortunate consequence of causing the App Domain to reload. This can really kill your scalability since the HttpRuntime.Cache (among other things) is blown away when App Domain is reloaded.
I reviewed some options for custom resource providers. First, I reviewed this article:
The implementation here uses a database back-end for storage of resources. With this solution, obviously there is no problem of ASP.NET monitoring App_GlobalResources and App_LocalResources files and invoking an App Domain reload.
This implementation uses on a private IDictionary member variable in each Resource Provider instance. This IDictionary’s keys correspond with all cultures supported in the resource data. The values in the IDictionary are themselves IDictionary object which provide all key-value pairs within each culture. These key-value pairs are the resource strings.
This example is easily adapted to read from .resx files instead of a database. (Note that the resource files would need to be placed in a directory that isn’t monitored by ASP.NET for changes.)
The issues I see with this implementation are as follows:
- Since the resource values are cached in member variables, they don’t change when the data source changes. The example code provides a ClearResourceCache() method to clear out the member variable. However, this method is not called automatically when specific resource are made.
Depending on application requirements, this may not be problematic; it could be OK to wait for the next App Domain restart for the resources to update.
- There may be multi-threading issues with this code. Note this line of code:
this._resourceCache[cultureName] = Resources;
Is it worth it to place a lock around the code that populates this member variable?
UPDATE -- locking has been added to the latest code download (not reflected in the article itself).
Another implementation that I reviewed:
This implementation is more geared to my specific problem – making modifications to .resx files without causing App Domain restarts.
In this implementation, the resources are not stored in member variables (contrary to the above implementation). Instead, they are stored in HttpRuntime.Cache. This has the benefit that we can make use of CacheDependency to monitor the .resx files for changes. This makes the files updateable, with the changes immediately reflected in the resource provider.
Still, there are drawbacks:
- In this implementation, the cached object is not an IDictionary. Instead, it is an IResourceReader object, which comes from a ResxResourceReader which is leveraged to read the .resx files. Consequently, every call to GetObject() actually loops through the IResourceReader object. So in the worse-case, the code iterates through every resource key looking for the item. This might be a performance issue for large resource files.
- To get around this limitation, some additional code would need to be written to loop through the resource reader and store it in an IDictionary object.
- How often will resources be updated by users?
- How quickly do resource updates need to be reflected in the web UI?