2

Hi– I'm planning to handle server side localization for error strings etc. based on the “Accept-Language” header, by setting the CurrentUICulture based on that header, but apparently it doesn’t flow though the async calls, below is a sample code to illustrate the problem, is there any default way of handling the localization for async calls?

   public async Task<HttpResponseMessage> GetAsync()
    {            
        //set the current ui culture, to say "fr-FR", based on "Accept-Language" header
        Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("**fr-FR**");  

       var task = httpClient.PutAsync(endpoint, content)            

        //do some processing

        var res  = await task;

        var culture = Thread.CurrentThread.CurrentUICulture.Name; **//ITS NOT necessarily fr-FR**

        //do some more processing
        //and handle localizations etc.

        return res;
    }

I'm looking for a cleaner/seamless way of handling localization for cases where there are real async operations esp. for the code following the await call

Edit: replaced Task.Run() with httpClient.PutAsync for clarity

j0k
  • 22,600
  • 28
  • 79
  • 90

1 Answers1

2

Task.Run and Task.Factory.StartNew do not have any context. That's an expected behavior. Context is preserved when you use the await keyword. So here's what you could do:

public static async Task<IEnumerable<string>> GetAsync()
{            
    //set the current ui culture, to say "fr-FR", based on "Accept-Language" header
    Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("fr-FR");

    //do some processing

    var s = await GetSomething();

    var culture = Thread.CurrentThread.CurrentUICulture.Name; //It's ja-JP

    return new[] { s, s };
}

public static Task<string> GetSomething()
{
    var cuture = Thread.CurrentThread.CurrentUICulture.Name; // It's fr-FR
    var tcs = new TaskCompletionSource<string>();
    Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("ja-JP");
    tcs.SetResult("<something>");
    return tcs.Task;
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • It's not guaranteed as the 3 parts (1. GetSomething() call 2. the code before and 3. the code after it) can potentially run on 3 different asp.net threads esp. if GetSomething() is a long running async operation. – user1929044 Dec 31 '12 at 09:43
  • If you are using the code in my example, they will run on the same context. If you create tasks with Task.Run or Task.Factory.StartNew they are not guaranteed to run on the same thread. – Darin Dimitrov Dec 31 '12 at 09:58
  • I'm looking for a cleaner/seamless way of handling localization for cases where there are real async operations like calls to another webservice etc, by default, the context won't be the same for such cases. – user1929044 Dec 31 '12 at 11:53
  • I don't understand what you mean. For calls to a web service, you cannot possible expect that the current culture info will make it to the web service. You will have to pass it as parameter. – Darin Dimitrov Dec 31 '12 at 12:24
  • 2
    yes but when it returns, the remaining part can potentially execute on a 3rd thread not necessarily on the original thread – user1929044 Dec 31 '12 at 15:45
  • Well, you haven't actually shown the code that is calling this function so it is difficult for me to help you any further. When this function returns what happens? Why would it execute on a different thread? – Darin Dimitrov Dec 31 '12 at 18:30
  • It's not about the caller of the GetAsync(), when the awaited task completes, the code following the await call in the GetAsync(), can potentially execute on a different thread. – user1929044 Jan 01 '13 at 08:09
  • And what makes you think so? AFAIK the `await` keyword preserves the execution context and the code that follows will run on the same thread. – Darin Dimitrov Jan 01 '13 at 11:24
  • nope, locale info is not part of the execution context, can be verified thru debugger. Also, as it's async, initial thread won't be blocked for the await to complete. – user1929044 Jan 02 '13 at 04:29
  • So you expect to set the locale info inside the asynchronous call and read the result outside even if the result outside could execute before? Sorry but I am really confused about what you are trying to do. Maybe a simple example illustrating the problem could help. – Darin Dimitrov Jan 02 '13 at 06:25
  • 1
    The sample given in the question sets the current ui culture, to say "fr-FR", based on "Accept-Language" header before the await call, one approach is we can set the current ui culture again after each await call, to say "fr-FR", based on "Accept-Language" header. The ask was if this can be done in a seamless way, looks like that's not possible. Anyways, thanks Darin for the prompt responses. – user1929044 Jan 02 '13 at 10:53
  • In the example you provided, the cultureinfo that you set before the async call should be preserved after you await for it. Did you somehow observed that this is not the case? Also normally if you specify in the `` element in your web.config to `Auto` you don't need to be setting the current thread culture info from the Accept-Language header. This will be automatically setup by ASP.NET. – Darin Dimitrov Jan 02 '13 at 10:58
  • nope, it's not getting preserved, if the code following await happens to running in a different thread. Also, the culture info is not static here (it should match with the accept-language header from the client), so element can't be used. – user1929044 Jan 02 '13 at 14:36
  • The `` element can be used. It's default value is `"auto"`. If you keep this default value, that's exactly what's gonna happen - the `Thread.CurrentThread.CurrentCulture` and `Thread.CurrentThread.CurrentUICulture` will be populated from the Accept-Language request header. So they won't be static but will vary based on the client browser settings. – Darin Dimitrov Jan 02 '13 at 14:52
  • @DarinDimitrov I've got the same problem, I suppose. Here: http://stackoverflow.com/questions/20067053/async-call-to-the-wcf-service-doesnt-preserve-currentculture. The CurrentCulture isn't preserved in my case. Should it really be preserved? – Dmitrii Lobanov Nov 19 '13 at 09:01