I’ve been talking for some time about about a localization provider I’ve been working on off and on for my session at ASP.NET Connections next week. I was finally able to post a small sample of what the provider does and what the admin interface looks like as part of my wwHoverPanel AJAX samples here:
This actually worked out well as I can use the Resource Admin form both in my Intro to Ajax and the Data Driven Localization session <s>. Here's a screen shot of the Web based localization administration interface:
There's more information on the provider etc. that can be found here:
The provider is a data-driven ASP.NET ResourceProvider and ResourceManager implementation against SQL Server data. It pulls data through a data layer into ResourceProvider. Building a ResourceProvider is pretty straight forward in ASP.NET although it’s not well documented – most of the code to implement a ResourceProvider is completely boiler plate and in fact there are only 2 data interface points in my provider code. The hard part I suppose is coming up with the ResourceProvider code that works in all situations both at compile time (ASP.NET uses the REsourceProvider at compile time to actually stick the Resource Expressions into the Control Tree code of the page both for Implicit and Explicit Resources) as well as at runtime.
ASP.NET internal resource access goes only through ResourceProvider, so in theory you can build a ResoruceProvider and be done with it but if you build a custom provider you may also need to access the Resources outside of ASP.NET pages. The ASP.NET ResourceProvider is only used by the page framework and as far as I can tell it’s not accessible outside of it even in the HttpPipeline. I also don’t seen anyway to indirectly get access to the Provider other than Control.GetLocalResourceObject() and Control.GetGlobalResourceObject(), so while the provider works well in that context it’s also limited in scope.
So in addition to implementing a ResourceProvider a ResourceManager implementation is useful so that the resources can be accessed in non-ASP.NET environments. ResourceManager implementation is a bit more complicated as there are a few more pieces to implement and the implementation is uh – shall we say non-intuitive because there are no explicit interfaces, but only a ResourceManager base class to inherit from. To override a REsourceManager you subclass the stock .NET ResourceManager and override key methods. This is a little better documented than the ASP.NET code and my .NET Internationalization Book has been helpful in this process. This book is very good for general .NET Localization principles, but really weak on the ASP.NET portion of things. Hence my efforts here <s>… Nevertheless I’ve found the book extremely helpful in getting up to speed on localization issues in general.
As it turns out I created two ResourceProviders: wwDbResourceProvider and wwDbSimpleResourceProvider. The main provider implements a custom ResourceManager that talks to the data access layer, while the simple provider simply uses the ASP.NET ResourceProvider interface and directly talks to the data access layer bypassing the ResourceManager. Operation of both providers is identical, however, the simple provider is slightly faster as it avoids the overhead of passthrough calls to the ResourceManager.
I’ve read a bunch of information regarding performance of custom providers/managers including a reference in the above book that seems to suggest that a data-driven provider is going to be slower than the stock manager/provider.
I ran a bunch of performance tests and I was very pleasantly surprised that using the databased provider incurred no performance hit at all when using the simple provider (in fact it was slightly faster than the stock ResX provider) and about 1.5-2% slower operation using the full ResourceManager based implementation.
I’m not surprised by this really – the way ResourceProviders and ResourceManagers work in .NET is through caching, so the database is realistically accessed only for initially retrieving resources – after that .NET manages the resources in memory via the cached resourcekeys retrieved. So initial hit might be different although I doubt it’s any slower to look up records from a database vs. reading resources out of a ResX file on disk. In any case, performance is not really an issue between providers. However I found that turning off localization altogether has a more signifant 5% performance increase for pure rendering purposes.
Even that is not all that significant IMHO. These tests were set up with control only pages so they don’t do any data lookups or other ‘heavy lifting’. In fact, even with providers hooked up I was running these pages with 35 controls on them at around 1300 requests a second on my laptop (Running IIS 7/Vista Intel Core-Duo 2ghz). Adding any data access to these requests are going to have way more of an overhead hit than any of these localization hits.
Interactive Resource Editing
Anyway, this provider I built is for a project that requires localization to be accessible to localizers and ultimately to the end-users (or rather admins) of to the application, so what was needed is a rich mechanism for finding localizable resources on a page and being able to edit them interactively through a Web interface.
The sample form I posted is a small example form that includes a wwDbResourceControl on the content page. This control is optional, but when globally enabled (via Configuration Section switch), the control causes each localizable control on a page to show an icon next to it. You can click on the icon and it takes you straight to the localization form and if the resource exists highlights it and allows editing it.
The form is meant to help easily see what translations exist and make it easy to save and add new values. The form is AJAX driven with my wwHoverPanel library and the wwCallbackMethod component. Without AJAX functionality this interface would have been pretty clunky so most of the updates occur over simple proxy page callbacks of the AJAX interface which makes the application fairly responsive. I was toying with using ATLAS instead of HoverPanel but given the recent Beta 1 debacle I sure am glad I stuck with my own custom control and didn’t break my code. <s>
The form provides an overall resource editing interface so you can edit, add, delete resources. The interface pops up additional ‘popup’ windows inline so it’s a very client centric form (although there are a few tasks that go back to the server). For example to Add a new resource a window pops up that lets you enter the new resource as well as upload file based resources. Similarily there’s a Translation option that goes out to Google or BabelFish and provides a base translation option and lets you fill values.
Some of the more intrusive operations like deleting or renaming a resource set, and generating ResX based resources from the data resources post back to the server, but those requests are minimal.
A session at Asp.NET Connections?
I’m not exactly an expert at Localization – far from it. But I’ve been involved in a few projects that involve localization and I’ve found that for my own vertical applications it’s a tremendous asset to have a localization engine built into the application. I would say for several of my tools the number one question is how to localize the application. While in the past I’ve pointed people at ‘simply use ASP.NET Localization’ now there’s a better alternative. It’s also forced me to be a little more strict in terms of page layout to make sure that pages CAN be localized (ie. no static literals in text etc. <s>).
So, the session I’m doing at ASP.NET connections is not a typical Localization/Internationalization session in that I won’t be delving into every aspect of localization (heck that’s topic for a whole day’s worth of sessions <s>), but rather focus on the improvements in ASP.NET 2.0 and more specifically on the features that relate directly to creating custom resource providers. I’ll be talking about how resources are used in ASP.NET and then delve into how ResourceProviders work behind the scenes and how to implement one like the one shown in the demo. And the resource provider is of course provided so you can actually use the thing without fully understanding how it works.
So if you’re coming out to DevConnections this week, stop by the sessions (it’s a loony 8am session on Wednesday morning) and try to keep me from falling asleep…
I’ll be posting more information and probably download links after the conference next week.
Now if you’ll excuse me, I’ll have to pack for my red-eye flight this evening…
Other Posts you might also like