.NET MVC Core 3.1 本地化 UrlHelper 不采用当前文化
.NET MVC Core 3.1 Localization UrlHelper doesn't take the current culture
我正在将 .Net 4.7 应用程序转换为 .Net Core 3.1。我正在更新本地化部分。我遵循了一些示例,例如 localization-in-asp-net-core-3-1-mvc.
它工作正常,但我没有找到使 UrlHelper.Action 在没有精确文化的情况下工作的方法。
我想自动设置文化参数。它应该来自 userclaims,或者以前的请求文化,或者默认文化。
例如,如果 URL 是“/Home/Contact”,则 UrlHelper 或 HtmlHelper 生成的 link 将是 /Home/About。
如果当前 URL 是“/en/Home/Contact”,则 link 将生成为“/en/Home/About”。
如果用户通过身份验证,它应该是“/userCulture/Home/About”。
但是我不能强制我的路由模板只有“{culture=en}/{controller=Home}/{action=Welcome}/{id?}”因为 root url 必须可以访问并且 API url应该保持“api/somestufff”。
Startup.cs :
var supportedCultures = CultureHelper.Cultures.Select(a => new CultureInfo(a)).ToArray();
var requestLocalizationOptions = new RequestLocalizationOptions();
requestLocalizationOptions.SupportedCultures = supportedCultures;
services.AddLocalization();
services.Configure<RequestLocalizationOptions>(options =>
{
options.DefaultRequestCulture = new RequestCulture("fr", "fr");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
options.RequestCultureProviders.Insert(0, new RouteValueRequestCultureProvider() { Options = requestLocalizationOptions });
});
//......................................
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(name: "culture-route", pattern: "{culture=en}/{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
});
控制器:
[Route("api/somestufff")]
public async Task<IActionResult> Somestufff()
{ ... }
[Route("{culture:length(2)}/items/{number:int}/{permalink?}")]
public async Task<IActionResult> DisplayItem(int number, string permalink)
{ ... }
剃刀页面:
Url.Action("DisplayItem", "MyController",new { culture = ViewBag.Culture as string, number = 123, permalink = "permalink1235" })
// => /en/items/123/permalink1235 OK
Url.Action("DisplayItem", "MyController",new { number = 123, permalink = "permalink1235" })
// => /en/MyController/DisplayItem?number=123&permalink=permalink1235 KO
有没有办法让 Urlhelper 添加当前上下文中缺少的文化?
由于您使用的是 .NET Core,因此您应该使用 Tag helpers.
替换 Url.Action
方法
通过使用标签助手,您可以使用这样的东西:
<a asp-controller="MyController" asp-action="DisplayItem" asp-route-number="123">Click</a>
这显然不能解决您路线中的culture
,我们将在一分钟内解决。
当前处理a
标签上的asp-
属性的标签持有者由Microsoft.AspNetCore.Mvc.TagHelpers
中的AnchorTagHelper
class完成。
我们可以继承 class 并添加有关处理 culture
.
的功能
- 在
/TagHelpers
下的 MVC 项目中创建名为 CultureAnchorTagHelper
的 class
- 填写内容如下:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace YourMvcName.TagHelpers
{
[HtmlTargetElement("a", Attributes = ActionAttributeName)]
[HtmlTargetElement("a", Attributes = ControllerAttributeName)]
[HtmlTargetElement("a", Attributes = AreaAttributeName)]
[HtmlTargetElement("a", Attributes = PageAttributeName)]
[HtmlTargetElement("a", Attributes = PageHandlerAttributeName)]
[HtmlTargetElement("a", Attributes = FragmentAttributeName)]
[HtmlTargetElement("a", Attributes = HostAttributeName)]
[HtmlTargetElement("a", Attributes = ProtocolAttributeName)]
[HtmlTargetElement("a", Attributes = RouteAttributeName)]
[HtmlTargetElement("a", Attributes = RouteValuesDictionaryName)]
[HtmlTargetElement("a", Attributes = RouteValuesPrefix + "*")]
public class CultureAnchorTagHelper : AnchorTagHelper
{
public CultureAnchorTagHelper(IHttpContextAccessor contextAccessor, IHtmlGenerator generator) :
base(generator)
{
this.contextAccessor = contextAccessor;
}
private const string ActionAttributeName = "asp-action";
private const string ControllerAttributeName = "asp-controller";
private const string AreaAttributeName = "asp-area";
private const string PageAttributeName = "asp-page";
private const string PageHandlerAttributeName = "asp-page-handler";
private const string FragmentAttributeName = "asp-fragment";
private const string HostAttributeName = "asp-host";
private const string ProtocolAttributeName = "asp-protocol";
private const string RouteAttributeName = "asp-route";
private const string RouteValuesDictionaryName = "asp-all-route-data";
private const string RouteValuesPrefix = "asp-route-";
private const string Href = "href";
private readonly IHttpContextAccessor contextAccessor;
private readonly string defaultRequestCulture = "en";
public override void Process(TagHelperContext context, TagHelperOutput output)
{
// Get the culture from the route values
var culture = (string)contextAccessor.HttpContext.Request.RouteValues["culture"];
// Set the culture in the route values if it is not null
if (culture != null && culture != defaultRequestCulture)
{
// Remove the 'href' just in case
output.Attributes.RemoveAll("href");
RouteValues["culture"] = culture;
}
// Call the base class for all other functionality, we've only added the culture route value.
// Because the route has the `{culture=en}`, the tag helper knows what to do with that route value.
base.Process(context, output);
}
}
}
- 修改
Shared/_ViewImports.cshtml
删除当前的AnchorTagHelper
,使用我们新创建的tag helper如下:
@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.AnchorTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, YourMvcName
应用所有更改后,将在您使用标签助手时填充区域性。
我正在将 .Net 4.7 应用程序转换为 .Net Core 3.1。我正在更新本地化部分。我遵循了一些示例,例如 localization-in-asp-net-core-3-1-mvc.
它工作正常,但我没有找到使 UrlHelper.Action 在没有精确文化的情况下工作的方法。 我想自动设置文化参数。它应该来自 userclaims,或者以前的请求文化,或者默认文化。
例如,如果 URL 是“/Home/Contact”,则 UrlHelper 或 HtmlHelper 生成的 link 将是 /Home/About。 如果当前 URL 是“/en/Home/Contact”,则 link 将生成为“/en/Home/About”。 如果用户通过身份验证,它应该是“/userCulture/Home/About”。
但是我不能强制我的路由模板只有“{culture=en}/{controller=Home}/{action=Welcome}/{id?}”因为 root url 必须可以访问并且 API url应该保持“api/somestufff”。
Startup.cs :
var supportedCultures = CultureHelper.Cultures.Select(a => new CultureInfo(a)).ToArray();
var requestLocalizationOptions = new RequestLocalizationOptions();
requestLocalizationOptions.SupportedCultures = supportedCultures;
services.AddLocalization();
services.Configure<RequestLocalizationOptions>(options =>
{
options.DefaultRequestCulture = new RequestCulture("fr", "fr");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
options.RequestCultureProviders.Insert(0, new RouteValueRequestCultureProvider() { Options = requestLocalizationOptions });
});
//......................................
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(name: "culture-route", pattern: "{culture=en}/{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
});
控制器:
[Route("api/somestufff")]
public async Task<IActionResult> Somestufff()
{ ... }
[Route("{culture:length(2)}/items/{number:int}/{permalink?}")]
public async Task<IActionResult> DisplayItem(int number, string permalink)
{ ... }
剃刀页面:
Url.Action("DisplayItem", "MyController",new { culture = ViewBag.Culture as string, number = 123, permalink = "permalink1235" })
// => /en/items/123/permalink1235 OK
Url.Action("DisplayItem", "MyController",new { number = 123, permalink = "permalink1235" })
// => /en/MyController/DisplayItem?number=123&permalink=permalink1235 KO
有没有办法让 Urlhelper 添加当前上下文中缺少的文化?
由于您使用的是 .NET Core,因此您应该使用 Tag helpers.
替换Url.Action
方法
通过使用标签助手,您可以使用这样的东西:
<a asp-controller="MyController" asp-action="DisplayItem" asp-route-number="123">Click</a>
这显然不能解决您路线中的culture
,我们将在一分钟内解决。
当前处理a
标签上的asp-
属性的标签持有者由Microsoft.AspNetCore.Mvc.TagHelpers
中的AnchorTagHelper
class完成。
我们可以继承 class 并添加有关处理 culture
.
- 在
/TagHelpers
下的 MVC 项目中创建名为 - 填写内容如下:
CultureAnchorTagHelper
的 class
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace YourMvcName.TagHelpers
{
[HtmlTargetElement("a", Attributes = ActionAttributeName)]
[HtmlTargetElement("a", Attributes = ControllerAttributeName)]
[HtmlTargetElement("a", Attributes = AreaAttributeName)]
[HtmlTargetElement("a", Attributes = PageAttributeName)]
[HtmlTargetElement("a", Attributes = PageHandlerAttributeName)]
[HtmlTargetElement("a", Attributes = FragmentAttributeName)]
[HtmlTargetElement("a", Attributes = HostAttributeName)]
[HtmlTargetElement("a", Attributes = ProtocolAttributeName)]
[HtmlTargetElement("a", Attributes = RouteAttributeName)]
[HtmlTargetElement("a", Attributes = RouteValuesDictionaryName)]
[HtmlTargetElement("a", Attributes = RouteValuesPrefix + "*")]
public class CultureAnchorTagHelper : AnchorTagHelper
{
public CultureAnchorTagHelper(IHttpContextAccessor contextAccessor, IHtmlGenerator generator) :
base(generator)
{
this.contextAccessor = contextAccessor;
}
private const string ActionAttributeName = "asp-action";
private const string ControllerAttributeName = "asp-controller";
private const string AreaAttributeName = "asp-area";
private const string PageAttributeName = "asp-page";
private const string PageHandlerAttributeName = "asp-page-handler";
private const string FragmentAttributeName = "asp-fragment";
private const string HostAttributeName = "asp-host";
private const string ProtocolAttributeName = "asp-protocol";
private const string RouteAttributeName = "asp-route";
private const string RouteValuesDictionaryName = "asp-all-route-data";
private const string RouteValuesPrefix = "asp-route-";
private const string Href = "href";
private readonly IHttpContextAccessor contextAccessor;
private readonly string defaultRequestCulture = "en";
public override void Process(TagHelperContext context, TagHelperOutput output)
{
// Get the culture from the route values
var culture = (string)contextAccessor.HttpContext.Request.RouteValues["culture"];
// Set the culture in the route values if it is not null
if (culture != null && culture != defaultRequestCulture)
{
// Remove the 'href' just in case
output.Attributes.RemoveAll("href");
RouteValues["culture"] = culture;
}
// Call the base class for all other functionality, we've only added the culture route value.
// Because the route has the `{culture=en}`, the tag helper knows what to do with that route value.
base.Process(context, output);
}
}
}
- 修改
Shared/_ViewImports.cshtml
删除当前的AnchorTagHelper
,使用我们新创建的tag helper如下:
@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.AnchorTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, YourMvcName
应用所有更改后,将在您使用标签助手时填充区域性。