【问题标题】:.NET MVC Core 3.1 Localization UrlHelper doesn't take the current culture.NET MVC Core 3.1 本地化 UrlHelper 不采用当前文化
【发布时间】:2020-11-04 21:41:07
【问题描述】:

我正在将 .Net 4.7 应用程序转换为 .Net Core 3.1。我正在更新本地化部分。我遵循了一些示例,例如localization-in-asp-net-core-3-1-mvc。

它工作正常,但我没有找到一种方法让 UrlHelper.Action 在没有精确文化的情况下工作。 我想自动设置文化参数。它应该来自用户声明、以前的请求文化或默认文化。

例如,如果 URL 是“/Home/Contact”,则 UrlHelper 或 HtmlHelper 生成的链接将是 /Home/About。 如果当前 URL 为“/en/Home/Contact”,则链接将生成为“/en/Home/About”。 如果用户通过身份验证,则应该是“/userCulture/Home/About”。

但我不能只强制我的路由模板 "{culture=en}/{controller=Home}/{action=Welcome}/{id?}" 因为 root url 必须可访问并且 API url 应该保持 lile "api /一些东西”。

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 从当前上下文中添加文化,如果它丢失了?

【问题讨论】:

  • Url.Action 根据路由模板生成url。一般的模板是把文化放在根路由(/controller/culture/)之后。

标签: c# asp.net-core asp.net-core-mvc asp.net-core-3.1 asp.net-core-localization


【解决方案1】:

由于您在 .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 类完成。

我们可以继承该类并添加有关处理culture 的功能。

  1. 在你的MVC项目中/TagHelpers下创建一个名为CultureAnchorTagHelper的类
  2. 内容填写如下:
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);
        }
    }
}

  1. 修改Shared/_ViewImports.cshtml以删除当前的AnchorTagHelper,并使用我们新创建的标签助手如下:
@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.AnchorTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, YourMvcName

应用所有更改后,当您使用标签助手时,文化将被填写。

【讨论】:

  • 我会将您的答案标记为好的答案。我还是很失望。我必须重写我的应用程序的一千个链接中的每一个......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-09
  • 2015-04-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多