Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multilingual website using OWIN and asynchronous methods

Background

I'm creating a simple, multilingual website using ASP.NET 4.6, C#, OWIN pipeline on IIS (Microsoft.Owin.Host.SystemWeb), lots of asynchronous method calls and standard, global resource files (*.resx in App_GlobalResources). The website uses MVC5, WebAPI2 and Autofac as dependency resolver.

Problem

I can't correctly change the locale/culture of generated pages, because asynchronous methods use multiple threads per request and I can't find a way to set Thread.Current[UI]Culture for every thread associated with given request as those properties aren't synchronized. I would also like to stay with clean code without "async/await culture configuration" messing with useful code.

Code

Startup.cs

public void Configuration(IAppBuilder app)
{
    ...

    app.UseAutofacMiddleware(container);
    app.UseAutofacMvc();
    app.UseAutofacWebApi(httpConfiguration);
    app.UseWebApi(httpConfiguration);

    ...

    app.Use(async (ctx, next) =>
    {
        /* in production, detect based on current URL and/or cookie */
        var culture = new CultureInfo("pl_PL");

        CultureInfo.CurrentCulture = CultureInfo.CurrentUICulture = culture;

        await next.Invoke();
    });
}

SampleController.cs

public async Task<ActionResult> SayHello()
{
    // returns pl_PL message
    var msgA = Resources.Messages.HelloWorld; 

    await someService.doSthAsync();

    // returns system default (en_US) message
    var msgB = Resources.Messages.HelloWorld;

    return Content(msgA + " - " + msgB);
}

  1. Should I create a custom [AspNet]SynchronizationContext as suggested in this SO answer? If that is the case how should I do that?
  2. Should I give up on global resouorces as source of translations and use some other approach? If so, what (library?) could I use?
like image 474
Crozin Avatar asked Aug 20 '15 21:08

Crozin


1 Answers

What about using the Owing Globalization Library, it seems like it was created just for this purpose.

You can still use your resx to localize your resources, and it has great customization capabilities:

public void Configuration(IAppBuilder app)
{
    ...
    app.UseGlobalization(new OwinGlobalizationOptions("en-US",true)
       .DisablePaths("Content", "bundles")
       .Add("fr-FR", true).AddCustomSeeker(new CultureFromPreferences()));
}

I have tested the use of async/await and the culture is preserved:

    public async Task<ActionResult> About()
    {
        var msgA = Resources.Resources.About;

        await Task.Delay(1000);

        var msgB = Resources.Resources.About;

        ViewBag.Message = msgA + " - " + msgB;

        return View();
    }

Note: I'm not the author of the library, I happen to have used it before.

like image 170
Julien Lebot Avatar answered Oct 21 '22 12:10

Julien Lebot