Я реализую ASP. NET Core 3.1 WebApp с использованием Razor Pages , который должен поддерживать несколько культур. Он будет работать на Azure. Он также должен поддерживать Asyn c методы .
Я создаю пользовательский RequestCultureProvider
, чтобы я мог получить культуру из требований пользователяPrincipal, если вошел в систему, как предлагается Маттео . Если пользователь не заморожен, я хочу получить культуру из одного из значений по умолчанию RequestCultureProviders
:
- Строка запроса в URL
- Cook ie
.AspNetCore.Culture
- Настройка браузера Accept-Language
После получения культуры пользователя из любого источника я хочу сохранить ее в ". AspNetCore.Culture" cook ie . Таким образом, культура пользователя может быть получена на моих страницах Razor, используя
var culture = page.Request.Cookies[".AspNetCore.Culture"];
- Примечание. Установка значения Cook ответа ie приводит к тому, что такое же значение становится доступным в запросе cook ie, как описано Microsoft
Это кажется лучшим подходом, чем попытка получить культуру из текущего потока, потому что, похоже, возникает множество проблем, когда делая это с помощью методов asyn c, как описано в GitHub и SO - Keep CurrentCulture в async / await .
По сути, эти проблемы возникают из-за того, что начальный поток, используемый Default RequestCultureProviders для установки культуры, может быть не тем же потоком, который использовался для запуска моих методов asyn c, и поскольку нет гарантии, что эти разные потоки будут иметь ту же культуру, что и исходный поток, я не могу быть уверен в получение культуры пользователя на моих страницах, прочитав:
var culture = Thread.CurrentThread.CurrentCulture.
Поэтому я решил написать a настраиваемый RequestCultureProvider , который пытается получить язык и региональные параметры либо из ClaimsPrincipal пользователя, либо из RequestCultureProviders по умолчанию, а затем устанавливает его в Cook культуре ie перед возвратом требуемого ProviderCultureResult. Я реализовал это следующим образом:
public class MyRequestCultureProvider : RequestCultureProvider
{
public override async Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
{
string culture = "en";
if (httpContext == null)
throw new ArgumentNullException();
if (httpContext.User.Identity.IsAuthenticated)
culture = httpContext.User.GetCulture() ?? "en";
else
{
var count = Options?.RequestCultureProviders?.Count ?? -1;
for (var x = 1; x < count; x++)
{
var provider = Options.RequestCultureProviders[x]; //don't invoke initial provider as that's our one
var val = await provider.DetermineProviderCultureResult(httpContext);
if (val?.Cultures?.Count > 0)
{
culture = val.Cultures[0].ToString() ?? "en";
break;
}
}
}
if (httpContext.Request.Cookies[".AspNetCore.Culture"] != culture)
httpContext.Response.Cookies.Append(".AspNetCore.Culture", culture, new CookieOptions { Expires = DateTime.Now.AddDays(3), IsEssential = true });
return new ProviderCultureResult(culture, culture );
}
}
Пользовательский RequestCultureProvider добавляется в промежуточное ПО в Startup следующим образом:
var supportedCultures = new[]
{
new CultureInfo("en"),
new CultureInfo("en-US"),
new CultureInfo("de-CH"),
};
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseRequestLocalization();
app.UseHttpsRedirection();
app.UseStaticFiles();
...
}
public void ConfigureServices(IServiceCollection services)
{
services.Configure<RequestLocalizationOptions>(options =>
{
options.DefaultRequestCulture = new RequestCulture(culture: supportedCultures[0].Name, uiCulture: supportedCultures[0].Name);
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
options.AddInitialRequestCultureProvider(new MyRequestCultureProvider());
});
services.AddRazorPages();
}
ВОПРОСЫ:
- Почему Options null , когда я обращаюсь к нему в моем переопределенном методе DetermineProviderCultureResult ()? Это свойство базового класса, задокументированное Microsoft , так как его инициализировать?
- Как еще я могу получить значения культуры, установленные по умолчанию RequestCultureProviders? Вы заметите, что мой метод DetermineProviderCultureResult () является asyn c, поэтому простое чтение значения культуры, установленного в потоке, не кажется хорошей идеей.
- Как еще я могу получить культуру пользователя для использования в my asyn c Методы страницы?
Любые комментарии к моему коду также приветствуются.