I've been mostly playing around with new Auto-Culture switching in ASP.NET 2.0 and it seems that there are a coulpe of issues I've run into that I can't seem to work around using this mechanism.

 

I’ve posted about ways to switch cultures in code previously and that’s been working fine, but now that ASP.NET includes some page level functionality it might seem like a good idea to let ASP.NET do this for me.

 

But I’m running into some issues. One is the CurrencySymbol. Auto-culture switches also switch the currency symbol which in most situations is not what you want. While I want to show German content and number and date formatting I don’t want to show pricing in Euros.

 

With my old code I created a new CultureInfo object and then assigned it to the thread. On that object I could happily override the Currency symbol:

 

/// <summary>

/// Sets a user's Locale based on the browser's Locale setting. If no setting

/// is provided the default Locale is used.

/// </summary>

public static void SetUserLocale(string CurrencySymbol,bool SetUiCulture)

{

    HttpRequest Request = HttpContext.Current.Request;

    if (Request.UserLanguages == null)

        return;

 

    string Lang = Request.UserLanguages[0];

    if (Lang != null)

    {

        // *** Problems with Turkish Locale and upper/lower case

        // *** DataRow/DataTable indexes

        if (Lang.StartsWith("tr"))

            return;

 

        if (Lang.Length < 3)

            Lang = Lang + "-" + Lang.ToUpper();

        try

        {

            System.Globalization.CultureInfo Culture = new System.Globalization.CultureInfo(Lang);

            System.Threading.Thread.CurrentThread.CurrentCulture = Culture;

 

            if (!string.IsNullOrEmpty(CurrencySymbol))

                System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.CurrencySymbol =

                  CurrencySymbol;

 

            if (SetUiCulture)

                System.Threading.Thread.CurrentThread.CurrentUICulture = Culture;

        }

        catch

        { ;}

    }

}

But if I do the following in an Asp.NET page:

 

protected override void InitializeCulture()

{

   System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.CurrencySymbol = "$";

   base.InitializeCulture();

 }

 

I get:

Instance is read-only.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: Instance is read-only.

Source Error:

 
 
Line 24:     {
 
Line 25: 
 
Line 26:         System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.CurrencySymbol = "$"; 
 
Line 27:         base.InitializeCulture();
 
Line 28:     }

 

So it looks if I want to do this I can go back to assigning my own culture with:

 

protected override void InitializeCulture()

{

 

        wwWebUtils.SetUserLocale("$");

        base.InitializeCulture();

}

 

This works, but of course this defeats the whole purpose of using the ASP.NET auto culture detection in the first place.

 

Is there an easier way?

 

Caching Problems

I’ve also run into a problem with caching which even with using a VaryByCustom for culture doesn’t seem to do the right thing. If you use cultures and caching is active you have to be careful so that you don’t cache culture specific information. So I figured you can use:

 

<%@ OutputCache VaryByCustom="Culture" Duration="60" VaryByParam="none" %>                       

 

And then set up this code in global.asax:

 

public override string GetVaryByCustomString(HttpContext Context, string Custom)   

{

    if (Custom == "Culture")

    {

        return System.Globalization.CultureInfo.CurrentCulture.Name;

    }

   

    return base.GetVaryByCustomString(Context,Custom);

}

 

But this doesn’t actually work when Auto-Culture switching is enabled in a page. Xctually I’m not surprised. By the time ASP.NET is setting the locale for page level auto-culture detection, the cache is long done and has already returned its output it seems and that's exactly the behavior I see. If I run two browsers, one in English one in German, hit the page in English then switch to the German browser the German browser gets the English page.

 

If I switch back to my original SetUserLocale code in Application.BeginRequest the caching works correctly:

 

void Application_BeginRequest(object sender, EventArgs e)

{

    Westwind.Globalization.Tools.wwWebUtils.SetUserLocale("$");

}

 

Since this happens before the cache processing occurs the check for the VaryByCustom actually has an effect.

 

What am I missing here? Both of these issues seem like a glaring holes in the Auto-Culture switching in ASP.NET’s page mechanism.