Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
Markdown Monster - The Markdown Editor for Windows

Updated ASP.NET Database Resource Provider


:P
On this page:

A few years back I wrote an article on creating a custom ASP.NET Localization Resource Provider that described how to create a custom ASP.NET ResourceProvider and ResourceManger that get resources from a database. It’s an older article but it’s been one of the more popular ones on this site, and the resource provider described has been picked up (based on feedback received) by quite a good number of developers.

In the last month I put a bit of effort into cleaning up the original provider and the result is a more formal Westwind.Globalization library that I hope more people will check out and take advantage of.

In the process I added better documentation, set up a new home page, created a GitHub project for the source code (moved from the old Westwind Web Toolkit project) and created a NuGet package that makes it easy to integrate the provider into your own applications.

I also created a new Getting Started video:

that takes you through installing and setting up the provider, adding some resources using the resource editor, and then demonstrate a variety of ways that you can use the localized resources. It’s a combo Getting Started and basic features overview – check it out if you have a few minutes to spare.

Why now?

The provider’s been around for a number of years, and it’s been updated and bug fixes have been made based on user submissions and bug reports. But the project has been off the beaten track. There was the article with the download, and the library was embedded as part of the Westwind West Wind Toolkit that’s now been broken up into its smaller component parts as separate projects. Westwind.Globalization was one of the last small projects left mainly because some work was required to clean up some of the samples and go the final mile to create a redistributable version of the online Web Resource Editor.

Additionally, in the last year or so I’ve been involved in several apps that have made fairly heavy use of this provider and as part of those project I was able to add a number of enhancements that came up in the process. I found some time to smooth out some of the rough edges in the provider and front end integration pieces.

Among the enhancements:

  • Better support for resources in MVC/WebAPI – or any .NET app really (console, service, desktop)
    (you can use DbRest.T() anywhere, or generate strongly typed resources that work either with ResX or Db resources)
  • Improved standard ResourceManger implementation for any .NET application
  • New DbRes helper class that allows direct access to resources bypassing ResourceProviders
    (ie. no resource provider config required in ASP.NET)
  • Improved strongly typed resource generation
  • Much improved Db Resource –> Resx export capabilities
  • Updated JavaScript resource generation handler
  • Update online Web Resource Editor
  • NuGet Package

Database Resources?

A lot of times when I mention Database resources for localization I get: “Isn’t that really slow?” The answer to that is – nope, not really. Yes, resources *are* loaded from a database, but they are loaded only once per ResourceSet per locale. This means once resources are loaded and in memory, they stay there – the process is identical to using Resx resources except that the initial read of a resource set is done from a database rather than from assembly ResX resources. So while there’s a small db hit for first time resource load on each ResourceSet, over the lifetime of an ASP.NET/.NET application there’s not a significant performance difference.

Additionally this library has the ability to import and export resources from Resx resources, so you can pull in existing resources, edit them in the database while your application is in development, then when complete export the resources back out to Resx and use them that way. You can even generate strongly typed resources that work with either database or Resx resources simply by switching the ASP.NET ResourceProvider. However, I’ve found although a number of clients had the intention of doing this, they actually preferred running with the Db resources because it allowed them to change the resources on the fly in the application as needed, without having to recompile the app.

Database resources are incredibly useful in localized applications as it’s much easier to modify resources interactively. This resource provider includes an interactive ASP.NET Web based resource editor that allows editing and updating of resources in a running application. The ability to manage resources interactively and update them however, adds a ton of flexibility which is a big sticking point in many a localized application I’ve worked on in the past.

Additionally if you use this provider, it has the optional capability to automatically add new resource keys to the database as keys are accessed. So if you use a resource that doesn’t exist, the value of the key is used, but also the key can automatically be added to the database. You can then lookup all missing ‘values’ and localize those.

DbResource Provider Support

The DbResourceProvider works with standard ASP.NET localization schemes so everything that works with ResX resources also works with the database provider. The DbResourceManager also works in any .NET application including services, console apps and even desktop applications.

All of the following are supported in ASP.NET:

  • DbRes Helper (part of Westwind.Globalization)
    Say Hello: @DbRes.T("HelloWorld", "Resources")
  • HttpContext.GetGlobalResourceObject()
    Say Hello: @HttpContext.GetGlobalResourceObject("Resources", "HelloWorld")
  • Page.GetLocalResourceObject() (WebForms only)
    Say Hello: <%= GetLocalResourceObject("lblHelloWorldLabel.Text") %>
  • WebForms Control meta:resource tags (WebForms only)
    <asp:Label ID="lblHelloLabel" runat="server" meta:resourcekey="lblHelloWorldLabel"></asp:Label>
  • WebForms Control Resource expressions (WebForms only)
    <asp:Label ID="Label1" runat="server" Text="<%$ Resources:Resources,HelloWorld %>"></asp:Label>
  • You can also generate strongly typed resources (once generated)
    Say Hello: @Resources.Helloworld

Alternate Localization Scheme

ASP.NET localization is based on ResourceID localization. The idea is that you have a resource ID value and that value is then matched in a ResX file for each of the locales you want to localize for. Typically using this approach you create keys that are more like Ids, rather than values, which in a lot of ways can be limiting.

More and more customers I’ve worked with though prefer using direct translation – ie. rather than embedding resource Ids, they want to embed actual resource string values in the default language and then translate those values later.

For example imagine I have a resource embedded like this in an MVC application:

<legend>@DbRes.T("Your Details","Account")</legend>
<label>@DbRes.T("First Name")</label>
@Html.TextBoxFor(mdl => mdl.User.FirstName, 
new { @class = "input-block-level", placeholder = DbRes.T("First Name") }) <label>@DbRes.T("Last Name","Account")</label> @Html.TextBoxFor(mdl => mdl.User.LastName,
new { @class = "input-block-level", placeholder = DbRes.T("Last Name") })

For example Last Name is a Resource Id here, which is the default text used. Even if there’s no resource named "Last Name" in the resource set, Last Name will be returned. Later when you translate to other languages those values can then be added and the translated values will be returned instead.

DbRes.T(resourceid,resourceSet,localeId) for translate is a small helper method directly accesses the Db Resource manager to retrieve values and it’s an easy way to use the

Unlike the standard ASP.NET ResourceProvider and ResourceManager, DbRes.T() and also the ASP.NET DbResourceProvider and DbResourceManager all automatically return the resource key if the resource Id was not found, so that when there’s no match at the very least you get the resource key value, rather than an empty string which sucks! If you’ve ever loaded an application with missing ResX resources you know what I’m talking about – it’s no fun to have empty labels and buttons and other UI controls without any content :-) This ResourceProvider will always return something…

Using actual translated default values for ResourceIds makes it easy to get default content into a page.

Further, If I add

addMissingResources="true" 

to the provider configuration resources are automatically added if they are not found. This adds resources in the Resource Editor for easy later translation simply by running the app rather than having to manually add the resources.

This works surprisingly well as resources are added to the application as you run it and you access the actual values on pages.

There is a caveat here however, if you change a resource string in your markup you potentially break the link to your resources in the database. So you have to be aware to either leave the original resource key intact and add an actual default text value, or you can rename the resource name in the Web editor which is actually very easy (advantage database :-)).

Although I was resistant to work with this approach initially I’ve come to appreciate how easy it is to work with this setup. You get default resources always, and with keys added automatically you can easily localize and add new language later. The database manager also includes a method to cleanup resources that have entries with null values and no localization, so when you’re done localizing you can clear out any clutter in the db of resource values that don’t have any actual translated data.

Anyway – it’s something to consider when setting up a new localization project.

Check it out

If you are doing localization in your application and you’re looking to do it a little more dynamically then what you can do with Resx, check out the database resource provider described here. It’s easy to get started and it provides a ton of flexibility to get resources added easily interactively or under program control.

Resources

Posted in ASP.NET  Localization  

The Voices of Reason


 

Doug Dodge
April 07, 2014

# re: Updated ASP.NET Database Resource Provider

Rick,

This is pure gold. I don't have time to fool around with it but have forwarded a link to a local fellow who's big into internationalization by the name of Adam Wooten. Hopefully this will drive some work and traffic your way.

Bill Poiter
April 10, 2014

# re: Updated ASP.NET Database Resource Provider

Rick - this looks really promising. We've built our own implementation that's somewhat similar but we didn't take the time to put in all the embellishments that I see in this library. The Resource Editor and Resource Handler to serve JavaScript resources are things we didn't even consider. Will be checking this out in the next couple of days. Cheers.

James Mallard
April 14, 2014

# re: Updated ASP.NET Database Resource Provider

Nice work Rick! We're just starting to add localization to an existing app and this looks like it will make life a lot easier.

FWIW, the resource editor is a great idea, but it could need a little polishing. There are a few things that feel inconsistent - I think I might take a stab at cleaning those up on a fork.

Keep up the good work, man and thanks for making this available.

Rick Strahl
April 14, 2014

# re: Updated ASP.NET Database Resource Provider

@James - thanks for the kind words.

Re: Resource Editor - yes I know. The code base is pretty old. I cleaned it up a bit recently for better standalone operation and as a drop in for existing projects when I created the NuGet package. It works and is functional but it could definitely be done better, I agree. I've started a re-write a couple of weeks back on a local branch here - removing much of the WebForms related stuff reducing one of the dependencies and greatly cleaning up the WebForms based HTML to just plain HTML. But it'll take some time to hook up all the functionality again so it might take a bit. But it's coming...

Billl Yoergensen
April 14, 2014

# re: Updated ASP.NET Database Resource Provider

Does the JavaScript resource handler work without having to use the database provider? This looks really useful, but we have to use Resx resources and it would be nice to serve our server resources to JavaScript.

Rick Strahl
April 15, 2014

# re: Updated ASP.NET Database Resource Provider

@Bill - The Resource handler works with either the DbResource or Resx providers. There's a flag (on the helper method or the actual URL sent to retrieve the resources) that can be set to determine how the resources are retrieved and served.

Developer
June 30, 2014

# Localized strings to Html

Hi Rick, thanks for this great direction, whats your thoughts on applying the localized strings to HTML using javascript plugin or using some generic handler?

I mean Dres.T version in javascript which will detect all applicable controls and replace in one shot.

Rick Strahl
June 30, 2014

# re: Updated ASP.NET Database Resource Provider

@Developer - for the client side I tend to generate strongly typed resources (part of the globalization toolkit)

https://github.com/RickStrahl/Westwind.Globalization#javascript-resource-handler

and just use those directly using object names. This works as long as the resource IDs are safe JavaScript names.

var hw = Resources.HelloWorld;
 
// non type-safe name
var hw2 = Resources["Hello World 2"];


I also tend to create a DbRes.T() function in my apps that matches the behavior of the server class - where you can specify the name of the resource and resources set. This has been valuable when server side MVC style localization expressions to the client side

// server expression
Text: @DbRes.T("HelloWorld","Resources")
 
// client expression
Text: {{DbRes.T("HelloWorld","Resources")


The client side version simply exposes a global object/function that looks at the resources and objects that I've attached to a fixed location.

As to auto-assigning stuff - not a fan of that myself. There are too many things you need to consider such as naming coinventions, properties/attributes that values get assigned to etc. plus it won't really work if you use dynamic controls with things like Angular. I think it's simply better to be explicit about resource assignment.

john
October 01, 2014

# re: Updated ASP.NET Database Resource Provider

Would it be possible to use a MySQL database?

Rick Strahl
October 01, 2014

# re: Updated ASP.NET Database Resource Provider

The provider was designed for SQL Server, but it'd be fairly easy to modify the db access code to work with MySql. The SQL is very standard so if you provide the MySql provider it might just work.

Next update will have better provider support (Mongo and other SQL dialects) but for now you'd have to customize the DB access code.

Mike
October 22, 2014

# re: Updated ASP.NET Database Resource Provider

Could you please le us know where to start in order to change to a mySQL database? Thanks

Anders Bouvin
September 30, 2015

# re: Updated ASP.NET Database Resource Provider

Hi! Great library!

I'm having trouble getting strongly typed resources to work when running my application in a console application. My application is normally run as a windows service, but for test purposes I have an optional way of running it in a console application. Since I recently changed to using west wind for globalization I haven't yet tested how the resource manager works in the windows service environment. Part of my application is a web and in that context all works as expcted.

In my test console application I instantiate my application, myApp and then on regular timer intervals a call my myApp.ProcessQueue() method. As stated above in this context I can't get the DbResourceManager to work. I have tested a new approach of using a windows forms app as a host for my application. Then it all works just fine. I'm not sure what the differens is but I wouldn't be surprised if it hade something to do with application context. Have you tested strongly typed resources in a console application (where the resources reside in a referenced assembly)? If so, how did you get it working?

Do you by any chance know if running an application as a windows service works with wwg strongly typed resources?

I actually had some trouble getting som integration tests (VS unit test) working properly with the DbResourceManager. But once I found the line of code that set the ResouerceAccessMode it worked just fine. A suggestion from my part is that you try to emphasize how to use west wind globalization outside an ASP.NET web. Just putting some instructions in a separate chapter "How to setup wwg in a non-web app". I suggest this as I scrolled passed how to do it many times and tried to search the web for other resources to guide me.

Pliskin
April 26, 2017

# re: Updated ASP.NET Database Resource Provider

Hello,

This provider id helpful, I have a question; I have two web projects(ASP.NET MVC and Web Form), If I use this provider in MVC project and update resource texts, can I see the new text in web Form project without restarting?

Thank you


Rick Strahl
April 26, 2017

# re: Updated ASP.NET Database Resource Provider

@Pliskin - Localization resoures are cached by the location framework in ASP.NET - regardless which dev platform (MVC, WebForms) you use. You need to either restart the AppDomain, or if you're using the localiztion provider mentioned here you can force the resource cache to be cleared. But either way these operations have to be explicitly performed - they don't happen automatically.


Gerard
June 28, 2017

# re: Updated ASP.NET Database Resource Provider

Rick, first of all, thank you very much for this framework to allow flexible resources. We incorporated it in our webapplication and then expanded it by using a CustomDataAnnotation to allow DisplayAttributes to make use of the same resources.

Unfortunately we now experience that when switching from language and thereby switching to another resource, the DisplayAttribute gets cached and doesn't switch to the other resource. Do you have any experience with that and did you find any solution for it?

[edit] I firstly commented on the link below, but I overlooked this blogpost here where it is much more likely for you to reply to. So my apologies for doubleposting.

https://weblog.west-wind.com/posts/2009/Apr/01/Updated-WestwindGlobalization-Data-Driven-Resource-Provider-for-ASPNET


West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024