More on Locale in Windows Azure

A few days ago I published a short post on controlling the locale for Windows Azure Applications, turns out that a significant piece was missing – whilst all that was written was well and true for web applications, the story for WCF services is slightly different –

By default web services do not run in ASP.net compatibility mode, and without this, many system.web settings in the web.config do not take effect, the MSDN article Hosting and Consuming WCF Services contains the following paragraph (bold is mine) –

ASP.NET Compatibility Model

When hosting your WCF services in a load-balanced or even a Web-garden environment where subsequent requests in a session can be processed by different hosts or processes in the environment, you need out-of-process persistent storage for your session state. Out-of-the box WCF doesn’t support persistent storage for session state. Instead, WCF stores all its session state in memory. When your WCF services are hosted in IIS, you can end up with recycling scenarios, as described in the previous section. Instead of building persistent storage for sessions all over again, WCF relies on the ASP.NET implementation for session state. This approach has one serious limitation: you limit your services to HTTP.

ASP.NET session state is not the only feature that is supported by the ASP.NET compatibility mode. It also supports features such as the HttpContext, globalization, and impersonation, just like you are used to with ASP.NET Web services (ASMX). Refer to MSDN Help for the ASP.NET–specific features to enable out-of-process session state.

And so – if you wanted to use the <globalization> element to control the locale of WCF service you must ensure your services are running in ASP.net compatibility mode, as shown in the MSDN article, this can be done by adding the following attribute to the service implementation –

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public class Service1 : IService1

But to allow that you would also need to add the following entry to the web config –

  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>

If you’d rather not run in compatibility mode, an alternative is to set the thread’s UI culture, as shown in my previous post, in the service’s constructor.

Note: for completeness I should add that this applies to WebServiceHost and REST services as much as it does for ServiceHost and SOAP based services, I have tested both.

Locale on Windows Azure

Two of the benefits of using the Windows Azure platform is the ability to deploy applications globally and avoiding the need to manage the hardware as well the O/S; however – like everything else in life – this comes at some ‘price’, and one element is control over the environment.

In Windows Azure all instances are created with the en-US locale by default and if your application is deployed outside the US, and you’re not handling this properly, this may cause some confusion.

image

To demonstrate this I’ve create a simple application using the ASP.net template and added a textbox, a button and  a label

In the Page_Load I’ve updated the label with DateTime.Now.ToString() and when I run my application on my UK laptop I get the expected result –

image

However, deploying and testing this on Windows Azure the result is different – the date shown is in US format (MM/dd/yyyy) rather then the UK format (dd/MM/yyyy) –

image

The same issue exists when trying to parse a date – entering the date 30/1/2012 into the textbox and clicking on the button which includes the logic –

Label2.Text = DateTime.Now.ToString("MM/dd/yyyy");

result with the correct date displayed in the label when running locally, but an exception when running in Azure (as there’s no month 30, of course)

So – what can one do?

Well – theoretically one can change the locale on the machine, either by using remote desktop (hardly a scalable and reliable approach) or, better yet, by employing a startup task to do this, but this has the potential of confusing the fabric controller and generally speaking – one should not meddle with the O/S unnecessarily.

So – this should be handled at the application level rather than the system level, what’s are the options?

Well – in my simple scenario I could have simply provided the required format in my code – if I had my Page_Load logic as DateTime.Now.ToString(“dd/MM/yyyy”)  I would have avoided the different behaviour between environments, similarly I could have provided the format when parsing the date

IFormatProvider cultureInfo = new CultureInfo("en-GB",false);
Label2.Text = DateTime.Parse(TextBox2.Text,cultureInfo).ToString();

But this could be quite cumbersome for a real application.

Another option is to set the Culture on the thread of the application –

Thread.CurrentThread.CurrentCulture = new CultureInfo("en-GB");

but I would need to do this on every page load, so that might be a bit cumbersome as well (but that’s a good option when you need to set the culture based on the user request, for example)

For a blanket rule option, seems like the web config is the best option – simply add

   <globalization culture="en-GB"
       uiCulture="en-GB"
    /> 

to the system.web section of the web config and this culture will be applied to all requests.

A good summary of the options can be found here

Note: turns out there’s a bit more to the story, read my follow up post