Using ASP.NET Resources in JavaScript

If you use resources in your web application to localize your strings on the server side, you may have also felt the need to use the same resources in JavaScript. The thing is, there wasn’t any straightforward way to do it. Until now, that is! Smile

I wrote a simple handler that picks up whatever resources you have on your application and outputs them as JavaScript. Say you have something like this:

image

image

You will be able to use any of the resources in the Sentences like this:

   1: window.alert(Resources.Sentences.Something);

The format is: Resources.<FileName>.<KeyName>. If you have several resource files, each will be located under the Resources namespace.

The code for the handler is:

   1: public sealed class Resources : IHttpHandler
   2: {
   3:     public void ProcessRequest(HttpContext context)
   4:     {
   5:         Assembly asm = null;
   6:         Type appType = HttpContext.Current.ApplicationInstance.GetType();
   7:  
   8:         context.Response.ContentType = "text/javascript";
   9:  
  10:         if (appType.Namespace == "ASP")
  11:         {
  12:             asm = appType.BaseType.Assembly;
  13:         }
  14:         else
  15:         {
  16:             asm = appType.Assembly;
  17:         }
  18:  
  19:         IEnumerable<Type> resources = asm.GetTypes().Where(x => x.Namespace == "Resources").ToList();
  20:  
  21:         var l = context.Request.UserLanguages;
  22:  
  23:         if (context.Request.UserLanguages.Any() == true)
  24:         {
  25:             try
  26:             {
  27:                 Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(context.Request.UserLanguages.First());
  28:             }
  29:             catch
  30:             {
  31:             }
  32:         }
  33:  
  34:         context.Response.Write("var Resources = {};\n");
  35:  
  36:         foreach (Type resource in resources)
  37:         {
  38:             context.Response.Write(String.Format("Resources.{0} = {{}};\n", resource.Name));
  39:             
  40:             IDictionary<String, String> dict = resources.First().GetProperties(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetProperty).Where(x => x.PropertyType == typeof(String)).ToDictionary(x => x.Name, x => x.GetValue(null, null).ToString());
  41:  
  42:             foreach (String key in dict.Keys)
  43:             {
  44:                 context.Response.Write(String.Format("Resources.{0}.{1} = '{2}';\n", resource.Name, key, dict[key].Replace("'", "\'")));
  45:             }
  46:         }
  47:     }
  48:  
  49:     public Boolean IsReusable
  50:     {
  51:         get
  52:         {
  53:             return (true);
  54:         }
  55:     }
  56: }

You have to install it on the Web.config as an HTTP handler, on the <httpHandlers> section:

   1: <httpHandlers>
   2:   <add path="Resources.axd" verb="GET" type="MyNamespace.Resources, MyAssembly" validate="true" />
   3: </httpHandlers>

Do note that the handler code may be in a different assembly, which is good for reusing purposes.

And finally, you must reference the handler on the page:

   1: <script type="text/javascript" src="Resources.axd"></script>

And that’s it. Your feedback is welcome!

                             

14 Comments

  • Why just not serialize it with something like Json.NET ?

  • @hazzik:
    What for? What is the gain? This produces more readable code, IMO.

  • Also exposes your resources?

  • @Densial:
    What do you mean? It exposes the resources of the web application where it is run.

  • And then, how to use that in javascript?

  • @Riccardo: (by the way, nice name!)

    "You will be able to use any of the resources in the Sentences like this:

    window.alert(Resources.Sentences.Something);
    "

  • I am very interested in your post. The information in your post is very benefitable for me. Thanks for share this post.

  • @Densial:
    Yes, I see what you mean, sorry. Of course, you should only use this with resources that you don't mind exposing

  • Nice solution, but what about performance?
    It is translate resource in js classes after each call, isn't it? What about performance in this case? Is it possible to cache "Resources.axd" file?
    If it is generated per each request - is it possible to reduce this script and add only field that we are using for current view?

  • RredCat:
    Yes, you're right. This is just "proof of concept", of course, you can improve it in many ways, such as caching.

  • This is a very good article that I've also applied in my project. However, I just noticed that translations aren't handled very well. That is, there is no ability to select the language to include. Is there any way to do this?

  • Hi, Hendrik!
    What do you mean, can you explain, please?

  • when external assembly resources :
    public void ProcessRequest(HttpContext context)
    {
    context.Response.ContentType = "text/javascript";
    var asm = typeof(Resource).Assembly;
    IEnumerable<Type> resources = asm.GetTypes().Where(x => x.Namespace == "U3D.Risorse").ToList();
    context.Response.Write("var Resources = {};\n");
    foreach (Type resource in resources)
    {
    context.Response.Write(string.Format("Resources.{0} = {{}};\n", resource.Name));
    IDictionary<string, string> dict = resources.First().GetProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.GetProperty).Where(x => x.PropertyType == typeof(string)).ToDictionary(x => x.Name, x => x.GetValue(null, null).ToString());
    foreach (string key in dict.Keys)
    context.Response.Write(string.Format("Resources.{0}.{1} = '{2}';\n", resource.Name, key, dict[key].Replace("'", "\'")));
    }
    }
    public bool IsReusable => true;
    }

    in web.config IIS 7
    <system.webServer>
    <handlers>
    <add name="Resources" path="Resources.axd" verb="GET" type="MyNamespace.Resources, MyAssembly" validate="true" />
    </handlers>
    </system.webServer>

  • @Giiuseppe: yes, that is the generic approach for any type, thank you!

Add a Comment

As it will appear on the website

Not displayed

Your website