Многоязычный сайт с использованием OWIN и асинхронных методов

Фон

Я создаю простой многоязычный веб-сайт, используя конвейер ASP.NET 4.6, С#, OWIN в IIS (Microsoft.Owin.Host.SystemWeb), множество асинхронных вызовов методов и стандартных глобальных файлов ресурсов (*.resx в App_GlobalResources), На веб-сайте используются MVC5, WebAPI2 и Autofac в качестве зависимого преобразователя.

Проблема

Я не могу правильно изменить язык/культуру сгенерированных страниц, потому что асинхронные методы используют несколько потоков для каждого запроса, и я не могу найти способ установить Thread.Current[UI]Culture для каждого потока, связанного с данным запросом, поскольку эти свойства aren ' t синхронизирован. Я также хотел бы остаться с чистым кодом без "настройки конфигурации async/await", используя полезный код.

Код

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);
}

  • Должен ли я создать пользовательский [AspNet]SynchronizationContext, как было предложено в этом SO-ответе? Если это так, как мне это сделать?
  • Должен ли я отказаться от глобальных resouorces в качестве источника переводов и использовать какой-то другой подход? Если да, то какую (библиотеку?) Я мог бы использовать?

Ответ 1

Как насчет использования библиотеки глобализации задолженностей, похоже, что она была создана именно для этой цели.

Вы все равно можете использовать свой resx для локализации ваших ресурсов и обладает большими возможностями настройки:

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

Я тестировал использование async/wait, и культура сохраняется:

    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();
    }

Примечание. Я не автор библиотеки, я раньше использовал ее.

Ответ 2

Ответ Джо Энзмигера выглядит здесь следующим образом:

public override Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext     controllerContext, CancellationToken cancellationToken)
{
if (controllerContext.Request.Headers.AcceptLanguage != null && 
    controllerContext.Request.Headers.AcceptLanguage.Count > 0)
{
    string language = controllerContext.Request.Headers.AcceptLanguage.First().Value;
    var culture = CultureInfo.CreateSpecificCulture(language);
    HttpContext.Current.Items["Culture"] = culture;
    //Thread.CurrentThread.CurrentCulture = culture;
    //Thread.CurrentThread.CurrentUICulture = culture;
}

base.ExecuteAsync(controllerContext, cancellationToken); 
}

а затем в любой задаче вам понадобится культура:

var culture = HttpContext.Current != null ? HttpContext.Current.Items["Culture"] as CultureInfo : Thread.CurrentThread.CurrentCulture;