При желании можно переопределить культуру запроса через URL / маршрут в приложении ASP.NET Core 1.0
Я пытаюсь переопределить культуру текущего запроса. Я получил это работать частично с помощью обычаяActionFilterAttribute
.
public sealed class LanguageActionFilter : ActionFilterAttribute
{
private readonly ILogger logger;
private readonly IOptions<RequestLocalizationOptions> localizationOptions;
public LanguageActionFilter(ILoggerFactory loggerFactory, IOptions<RequestLocalizationOptions> options)
{
if (loggerFactory == null)
throw new ArgumentNullException(nameof(loggerFactory));
if (options == null)
throw new ArgumentNullException(nameof(options));
logger = loggerFactory.CreateLogger(nameof(LanguageActionFilter));
localizationOptions = options;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
string culture = context.RouteData.Values["culture"]?.ToString();
if (!string.IsNullOrWhiteSpace(culture))
{
logger.LogInformation($"Setting the culture from the URL: {culture}");
#if DNX46
System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo(culture);
System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo(culture);
#else
CultureInfo.CurrentCulture = new CultureInfo(culture);
CultureInfo.CurrentUICulture = new CultureInfo(culture);
#endif
}
base.OnActionExecuting(context);
}
}
На контроллере я используюLanguageActionFilter
.
[ServiceFilter(typeof(LanguageActionFilter))]
[Route("api/{culture}/[controller]")]
public class ProductsController : Controller
{
...
}
Пока это работает, но у меня есть две проблемы:
Мне не нравится заявлять{culture}
на каждом контроллере, так как он мне понадобится на каждом маршруте.У меня культура по умолчанию не работает с этим подходом, даже если я объявил его как[Route("api/{culture=en-US}/[controller]")]
по понятным причинам.Установка результатов маршрута по умолчанию тоже не работает.
app.UseMvc( routes =>
{
routes.MapRoute(
name: "DefaultRoute",
template: "api/{culture=en-US}/{controller}"
);
});
Я также исследовал в обычаеIRequestCultureProvider
реализация и добавить его вUseRequestLocalization
метод как
app.UseRequestLocalization(new RequestLocalizationOptions
{
RequestCultureProviders = new List<IRequestCultureProvider>
{
new UrlCultureProvider()
},
SupportedCultures = new List<CultureInfo>
{
new CultureInfo("de-de"),
new CultureInfo("en-us"),
new CultureInfo("en-gb")
},
SupportedUICultures = new List<CultureInfo>
{
new CultureInfo("de-de"),
new CultureInfo("en-us"),
new CultureInfo("en-gb")
}
}, new RequestCulture("en-US"));
но тогда у меня нет доступа к маршрутам там (я предполагаю, потому что маршруты сделаны позже в конвейере). Конечно, я также мог бы попытаться разобрать запрошенный URL. И я даже не знаю, смогу ли я изменить маршрут в этом месте, чтобы он соответствовал вышеуказанному маршруту с культурой в нем.
Передача культуры через параметр запроса или изменение порядка параметров внутри маршрута не является вариантом.
Оба URLapi/en-us/products
как мыapi/products
следует направить на тот же контроллер, где первый не меняет культуру.
Порядок, в котором будет определяться культура, должен быть
Если определено в URL, возьмите егоЕсли не определено в URL, проверьте строку запроса и используйте этоЕсли не определено в запросе, проверьте кукиЕсли не определено в cookie, используйтеAccept-Language
заголовок.2-4 делается черезUseRequestLocalization
и это работает. Также мне не нравится текущий подход к добавлению двух атрибутов к каждому контроллеру ({culture}
в пути и[ServiceFilter(typeof(LanguageActionFilter))]
).
Редактировать: Я также хотел бы ограничить количество допустимых локалей одним набором вSupportedCultures
собственностьRequestLocalizationOptions
перешел кUseRequestLocalization
.
IOptions<RequestLocalizationOptions> localizationOptions
вLanguageActionFilter
выше не работает, так как возвращает новый экземплярRequestLocalizationOptions
гдеSupportedCultures
всегдаnull
и не тот, который передан.
FWIW это RESTful проект WebApi.