ASP.NET provides the ability to use strongly typed resources for Global resources that are contained in App_GlobalResources. This is a nice feature, but it has a pretty major flaw as it's implemented right now.
The way this works is that you have your Resx file in App_GlobalResources and ASP.NET will at compile time generate a class from each of the resource sets (each distinct invariant .resx file) defined. For example a generated class looks like this:
public class resources
{
// Fields
private static CultureInfo resourceCulture;
private static ResourceManager resourceMan;
// Methods
internal resources();
// Properties
public static string CouldNotCreateNewCustomer { get; }
public static string CouldNotLoadCustomer { get; }
[EditorBrowsable(EditorBrowsableState.Advanced)]
public static CultureInfo Culture { get; set; }
public static string CustomerSaved { get; }
[EditorBrowsable(EditorBrowsableState.Advanced)]
public static ResourceManager ResourceManager { get; }
public static Bitmap Sailbig { get; }
public static string Today { get; }
public static string Yesterday { get; }
}
Note that this works both with stock ASP.NET projects as well as with WAP. With WAP it's a bit more explicit - you can examine the class in the IDE, where with ASP.NET stock projects this class gets generated at runtime and embedded into the App_GlobalResources assembly that gets dynamically generated. In WAP you get the standard project behavior with a Properties namespace with the resources underneath it.
For the stock projects generated class shown above you can see that the ASP.NET creates a ResourceManager instance field. But hold on here - a ResourceManager is not the proper component that should be referenced for an ASP.NET Resources. ASP.NET works with ResourceProviders which can be swapped via hookups in web.config. You can basically create a custom resource provider and use it instead of the default ResX provider. ResourceManager works, but it's not hooked into the ASP.NET resource architecture.
However, the class generated can't deal with this since it doesn't work with a ResourceProvider, but simply uses a ResourceManager which is hardcoded in the static property get for the ResourceManager:
public static ResourceManager ResourceManager
{
get
{
if (object.ReferenceEquals(resourceMan, null))
{
ResourceManager temp = new ResourceManager("Resources.resources", typeof(resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
This means that if you change the ResourceProvider this sort of strongly typed global resource will no longer work. But even with Resx resources this is a problem: By creating a new ResourceManager ASP.NET is effectively duplicating the resources that might be used by the ResourceProvider (for example if you use those same resources for Explicit or Implicit resource markup strings).
Either way this doesn't sound like a good way to go.
It seems to me if ASP.NET is generating this class anyway, why couldn't it generate code like this instead:
using System;
using System.Web;
namespace AppResources
{
public class Resources
{
public static System.String Yesterday
{
get { return (System.String) HttpContext.GetGlobalResourceObject("Resources","Yesterday"); }
}
public static System.Drawing.Bitmap Sailbig
{
get { return (System.Drawing.Bitmap) HttpContext.GetGlobalResourceObject("Resources","Sailbig"); }
}
public static System.String Today
{
get { return (System.String) HttpContext.GetGlobalResourceObject("Resources","Today"); }
}
public static System.String CustomerSaved
{
get { return (System.String) HttpContext.GetGlobalResourceObject("Resources","CustomerSaved"); }
}
public static System.String CouldNotCreateNewCustomer
{
get { return (System.String) HttpContext.GetGlobalResourceObject("Resources","CouldNotCreateNewCustomer"); }
}
public static System.String CouldNotLoadCustomer
{
get { return (System.String) HttpContext.GetGlobalResourceObject("Resources","CouldNotLoadCustomer"); }
}
}
}
This would ensure that the Provider settings are respected so you could use any ResourceProvider and this would also take care of the duplication issue as the same Provider is used that ASP.NET uses for markup resources.
A while back I created some helper routines as part of my Data Resource Provider that let you run through the ResX resources (or any ResourceSet) and generate a strongly typed class like above.
Class:
http://www.west-wind.com/tools/wwDbResourceProvider/docs/_1Y7185CTQ.htm
Code (as part of the whole provider):
http://www.west-wind.com/files/confererences/conn_Localization.zip
This works, but it'd be nice if this would work like this out of the box instead. Given that ASP.NET generates this anyway - why not generate the 'right' code? <s>
Other Posts you might also like