IViewLocalizer 有时在 .net core 3.1 中不起作用

IViewLocalizer does not work sometimes in .net core 3.1

我在我的应用程序中配置了一个全球化,问题是当我调用一个进行服务调用的控制器方法时,它不起作用(实际上返回密钥)。当我删除服务调用并且方法仍然为空时,它工作正常。

 public async Task<IActionResult> Index(int id)
 {
     var item = _mapper.Map<ItemViewModel>(await _itemService.GetById(id));
     item.ItemImages = await _itemImageService.GetImageByItemId(id);
     return View(null);
 }

剃刀页面

@using Microsoft.AspNetCore.Mvc.Localization
@inject IViewLocalizer Localizer
@{
    ViewData["Title"] = "Index";
}


<div class="container" style="margin:100px 0 0 0">
    <h1>@Localizer["Category"]</h1>
</div>

Startup.cs

 services.AddLocalization(opts => opts.ResourcesPath = "Resources");
 services.AddMvc()
         .AddViewLocalization(
              LanguageViewLocationExpanderFormat.Suffix,
              opts => opts.ResourcesPath = "Resources")
         .AddDataAnnotationsLocalization();
  
 services.AddControllersWithViews();
 services.AddRazorPages();

配置

var supportedCultures = new[]
{
      new CultureInfo("am-AM"),
      new CultureInfo("en-US"),
      new CultureInfo("ru-RU")
};
app.UseRequestLocalization(new RequestLocalizationOptions
{
      DefaultRequestCulture = new RequestCulture("en-US"),
      SupportedCultures = supportedCultures,
      SupportedUICultures = supportedCultures
});

所以我从 ASP.NET 核心团队那里得到了答案。在这里分享它,以便遇到此问题的其他人 post 可以找到它。

观察到的行为的原因是 .NET Core 将 CultureInfo 存储在 AsyncLocal 上,这导致区域性存储在给定异步控制流的本地 - 在本例中为异步方法。

ASP.NET 团队分享的示例有助于进一步阐明这一点:

static async Task Main(string[] args)
{
    await SetCultureActionFilter();
    Console.WriteLine(CultureInfo.CurrentCulture);
}

static async Task SetCultureActionFilter()
{
    await Task.Yield();
    CultureInfo.CurrentCulture = new CultureInfo("fr-FR");

    Console.WriteLine(CultureInfo.CurrentCulture);
}

以上代码将有以下输出:

fr-FR
en-US

解决方案

不应在动作过滤器/动作执行上下文中设置文化。 相反,应该使用已经在您的代码中注册的 LocalizationMiddleware。正如文档所建议的,对于生产应用程序,建议使用 CookieRequestCultureProvider.DefaultCookieName cookie 来指定区域性。 cookie 具有以下格式:c=%LANGCODE%|uic=%LANGCODE%。所以你可以将它设置为 c=am|uic=am 并且你应该获得与所需文化匹配的资源。

这是一个您可以用来更改页面文化的示例操作:

public IActionResult ChangeCulture(string culture)
{
    Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName, $"c={culture}|uic={culture}");
    return RedirectToAction("Index");
}

然后,当用户单击相应的文化按钮时,只需调用 /[controller]/changeculture?culture=am 处的操作作为示例。

或者,您可以通过 ?culture=am-AM 查询字符串参数指定区域性。

希望对您有所帮助!