Programmatically Retrieving Items From Resource Files In .Net

If you are working on an international application, then you are almost certainly using resource files. In ASP.NET (including ASP.NET MVC) there are a number of different types of resource file including global (App_GlobalResources) and local (App_LocalResources) but most people will find the satellite assembly approach the best choice. When referencing resources from within your application, using strongly typed names is preferable in most cases but there are times where a more automated approach may be more succinct and less error prone. This article explains a simple way of querying a resource file for a subset of resources.

I was recently working on a registration form for a client and came across a very large method in a helper class that added a huge number of resource strings to a SelectListItem array. This array was then added to a view model and used to populate a DropDownList on an MVC view. A snippet of the code is displayed below:

public IEnumerable<SelectListItem> GetCountryList()
{		
  return new[] 
  {                
    new SelectListItem {Value = "AL", Text = Resources.ListData.ListOfCountries_AL},
    new SelectListItem {Value = "DZ", Text = Resources.ListData.ListOfCountries_DZ},
    new SelectListItem {Value = "AD", Text = Resources.ListData.ListOfCountries_AD},
    new SelectListItem {Value = "AO", Text = Resources.ListData.ListOfCountries_AO},
    new SelectListItem {Value = "AI", Text = Resources.ListData.ListOfCountries_AI},
    new SelectListItem {Value = "AQ", Text = Resources.ListData.ListOfCountries_AQ},
    new SelectListItem {Value = "AG", Text = Resources.ListData.ListOfCountries_AG},
    new SelectListItem {Value = "AR", Text = Resources.ListData.ListOfCountries_AR},
    new SelectListItem {Value = "AM", Text = Resources.ListData.ListOfCountries_AM},
    new SelectListItem {Value = "AW", Text = Resources.ListData.ListOfCountries_AW},
    ...
  }
}

This continued for all 225 countries in the resource file. There were several other similar methods that retrieved different data in the same way. The original developer had written a TODO within the method explaining that this was not an ideal approach and an automated way of populating the list of countries would be better. The funny thing is that doing it programmatically would have been much quicker than the copy / paste / edit approach that he chose. Let's look at how to do it:

First we create a helper method that takes in the prefix and ResorceManager. By taking in the ResourceManager, we allow the method to be used on any resource file. Using simple query syntax, we can filter the set, extract the values that we want and return the key (minus the prefix) and value, both as strings. Note that we are using Substring(prefix.Length + 1) to remove the prefix and the underscore in the key name to return the unique part of the key for each item.

private static IEnumerable<KeyValuePair<string, string>> GetItemsFromResource(string prefix, 
  ResourceManager resourceManager)
{
  var resourceSet = resourceManager.GetResourceSet(
    Thread.CurrentThread.CurrentUICulture, false, true);

  return from entry in resourceSet.Cast<DictionaryEntry>()
       where entry.Key.ToString().StartsWith(prefix)
       select new KeyValuePair<string, string>(
       entry.Key.ToString().Substring(prefix.Length + 1), entry.Value.ToString());
}

We then call this helper method from the original GetCountryList method and convert the key value pairs to SelectListItems, ready to be bound to a DropDownList on the view.

public IEnumerable<SelectListItem> GetCountryList()
{
  var items = new List<SelectListItem>(
    GetItemsFromResource("ListOfCountries", ListData.ResourceManager).Select(
      item => new SelectListItem {Text = item.Value, Value = item.Key}));

  return items;
}

If we repeat this for all other methods in the class, we can remove hundreds of lines of code. Another benefit is the fact that if a new item is added to the resource file, it will automatically be picked up without any code change required. One further benefit is that the value property of the SelectListItem now comes from the resource file rather than being hardcoded, reducing the likelihood of mistakes.

Conclusion

Resource files are by far the easiest and most maintainable way of globalising your application. In the vast majority of cases, using the properties on the strongly typed class created by Visual Studio is the best approach. There are times however, where you might prefer to query the resource file dynamically. This article shows how trivial it is to do so and provides example code for returning all items in the resource file that have a specified prefix. This is ideal for retrieving lists that are used to populate form dropdowns such as countries or currencies.

Useful or Interesting?

If you liked the article, I would really appreciate it if you could share it with your Twitter followers.

Share on Twitter

Comments

Comments are now closed for this article.