В настоящее время я портирую приложение из ASP.NET 4 в ASP.NET Core. Я хочу использовать маршрутизацию на основе атрибутов, имея возможность локализовать URL-адреса.
Устаревшее приложение использовало подход, использующий пользовательский IDirectRouteProvider
. Поскольку я не нашел соответствующего типа в ASP.NET Core, я выбрал решение, основанное на https://www.strathweb.com/2015/11/localized-routes-with-asp-net-5-and-mvc-6/. Вот реализация, использующая IApplicationModelConvention
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(o =>
{
o.Conventions.Insert(0, new LocalizedRouteConvention());
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseRequestLocalization(new RequestLocalizationOptions { ... });
app.UseMvc();
}
}
public class LocalizedRouteConvention : IApplicationModelConvention
{
public void Apply(ApplicationModel application)
{
foreach (var controller in application.Controllers)
{
foreach (var action in controller.Actions)
{
var attributes = action.Attributes.OfType<RouteAttribute>().ToArray();
if (!attributes.Any()) return;
foreach (var attribute in attributes)
{
SelectorModel defaultSelector = action.Selectors.First();
foreach (var localizedVersion in GetLocalized(attribute.Template))
{
if (!action.Selectors.Any(s => s.AttributeRouteModel.Template == localizedVersion.Template))
{
action.Selectors.Insert(0, new SelectorModel(defaultSelector)
{
AttributeRouteModel = localizedVersion,
ActionConstraints =
{
new CultureActionConstraint { Culture = ((LocalizedRouteAttribute) localizedVersion.Attribute).Culture }
}
});
}
}
}
}
}
}
}
public class LocalizedRouteAttribute : RouteAttribute
{
public LocalizedRouteAttribute(string template) : base(template)
{
}
public string Culture { get; set; }
}
public class CultureActionConstraint : IActionConstraint
{
public string Culture { get; set; }
public int Order => 0;
public bool Accept(ActionConstraintContext context)
{
return CultureInfo.CurrentCulture.TwoLetterISOLanguageName == Culture;
}
}
Теперь этот подход работает, и локализованные маршруты доступны, только когда установлена правильная культура запросов. Однако, когда я использую Html.ActionLink(...)
или любую другую функцию, которая использует IUrlHelper.GetVirtualPathData()
, маршрут по умолчанию возвращается вместо локализованного.
Насколько я понимаю, IUrlHelper
будет проверять IRouteConstraint
маршрута, но, похоже, он не учитывает IActionConstraint
. К сожалению, я не нашел способа установить пользовательские IRouteConstraint
s в своих IApplicationModelConvention
.