Dynamic resource path that requires url param

Apr 28, 2010 at 3:05 PM

Hi,

Great product - but I'm running into a problem with a dynamically-generated javascript file that requires a url parameter to be specified. Basically, what I have is a javascript file generated by a view that contains localized constants used in other scripts.

In order to ensure the browser caches one version of this per user language, I need to append the user's current language to the javascript file name at runtime (for example: /jsfile/generatejsresources.aspx?language=en-US) where "en-US" is substituted with the CurrentUICulture.Name at runtime.

Is something like this possible using Combres? I'm thinking that this could possibly be done with a version generator that appends the ui culture along with the version number - but I wasn't sure if that was a viable solution or not.

Thanks in advance for any insights!

-Dan

Apr 28, 2010 at 5:44 PM

Just to follow up on my own thread here - I don't think this will be possible with a Version Generator since the CurrentUICulture and CurrentCulture don't seem to be transfered to the thread that does the script downloading (so they are always equal to "en-US" regardless of what they're set to on the Web thread) - so that looks like a dead-end...any other suggestions?

Coordinator
May 2, 2010 at 8:06 AM

Unfortunately, there's no easy way to implement that.  Too many elements of the design work on the assumption that there's only one content per URL (resource) at any point of time.  Therefore, if your script handler outputs different contents for separate requests, it may break many things like version generation, per-resource caching and auto-change monitoring.  In the future, I may be able to come up with some generic solution that supports that kind of scenario (i.e. per-request specific content), but for now, I don't see it will be supported by Combres any soon. 

So instead of waiting for such generic solution, I suppose you can roll out your custom code on top of Combres.  For example, if you suppose like 4 languages in your app, you can define 4 resource sets corresponding to those languages.  Then inside the code of the pages using that set, you can write code to pick right resource set, e.g. WebExtensions.CombresLink("myset" + cultureString).  Of course, if your app supports a lot more languages or it should work against any particular language denoted in the HTTP request, then that solution may not suffice.

 

May 2, 2010 at 5:05 PM

Looks like you could benifit from a more generic Culture-handler. Imagine being able to request EVERY resource in a specific language by just prepending a culture-string

ie.  /en-US/jsfile/generatejsresources.aspx, /da-DK/jsfile/generatejsresources.aspx etc. and inside generatejsresources.aspx you can easily query the current language on CultureInfo.CurrentUICulture

This can be done with the following HttpModule that you just need to register in your web.config

public class GlobalizationModule : IHttpModule
    {
        private static object _lock = new object();

        private GlobalizationSection globalizationSection;

        public HttpContext Context
        {
            get { return HttpContext.Current; }
        }

        private Dictionary<string, CultureInfo> Cultures
        {
            get
            {
                Dictionary<string, CultureInfo> list = Context.Application["cultureinfos"] as Dictionary<string, CultureInfo>;
                if (list == null)
                {
                    lock (_lock)
                    {
                        if (list == null)
                        {
                            list = CultureInfo.GetCultures(CultureTypes.AllCultures).ToDictionary(c => c.Name);
                            Context.Application["cultureinfos"] = list;
                        }
                    }
                }

                return list;
            }
        }

        private void Resolve(object sender, EventArgs e)
        {
            HttpRequest request = Context.Request;
            CultureInfo ci = ResolveCultureByPage();

            Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = ci;
            OnPostCultureResolved();
        }

        protected virtual void OnPostCultureResolved()
        {
            HttpRequest request = Context.Request;

            string culture = null;
            try
            {
                culture = request.Url.AbsolutePath.Substring(1, request.Url.AbsolutePath.IndexOf("/", 1) - 1);
            }
            catch (ArgumentOutOfRangeException) { }

            Dictionary<string, CultureInfo> list = Cultures;
            if (!String.IsNullOrEmpty(culture) && list.ContainsKey(culture))
            {
                string rewriteUrl = request.RawUrl.Replace("/" + culture, String.Empty);
                Context.RewritePath(rewriteUrl);
            }
        }

        protected virtual CultureInfo ResolveCultureByPage()
        {
            HttpRequest request = Context.Request;
            CultureInfo ci = CultureInfo.CurrentCulture;

            string culture = null;
            try
            {
                culture = request.Url.AbsolutePath.Substring(1, request.Url.AbsolutePath.IndexOf("/", 1) - 1);
            }
            catch (ArgumentOutOfRangeException) { }

            Dictionary<string, CultureInfo> list = Cultures;
            if (!String.IsNullOrEmpty(culture) && list.ContainsKey(culture))
            {
                ci = list[culture];
            }

            return ci;
        }

        void IHttpModule.Init(HttpApplication appl)
        {
            appl.PostAuthorizeRequest += new EventHandler(Resolve);
        }

        void IHttpModule.Dispose() { }
    }

What it does it to Intercept all requests and look for a culture-string in the start of the URI. If a valid string is found the current cultureinfo is set according to the string and the string is removed so the URI maps correctly to the original file.

May 2, 2010 at 7:13 PM
Edited May 2, 2010 at 7:14 PM

Buu,

Thanks for taking the time to respond (twice!) - I think this is a good line of reasoning (and will probably go this route in my final impl).

I wonder if something along the lines of "Filters" for the url would be a good generic solution for Combres; for example, allow for the url to be manipulated in the same way you currently allow for content to be manipulated? I'm not sure if this is a common enough issue to warrant something like this, but food for thought in either case.

Given the impact Combres will have on my current project, I would be more than happy to share any solution(s) I come up with with you so they could eventually find their way back into Combres.

Regards,

-Dan

Coordinator
May 3, 2010 at 2:47 PM

Hi Dan, you're welcome. 

Please note that if you decide to use the HTTP module proposed by user @burningice, you still need to define separate resource sets for resources in different cultures.

Thanks for suggesting more ideas.  I will certainly think about a generic solution for this kind of situation.  Also, I will greatly appreciate any code/solution contribution that you can bring to Combres.

Regards,

Buu