MVC .net 站点 URL 中具有语言属性的自定义路由

Kev*_*haw 5 .net asp.net-mvc localization routes

我有一个网站需要本地化为多种不同的语言。为了实现这一目标,我按照此处的教程进行操作 https://www.ryadel.com/en/setup-a-multi-language-website-using-asp-net-mvc/ 在我的路线配置中,我有:

routes.MapRoute(
                name: "DefaultLocalized",
                url: "{lang}/{controller}/{action}/{id}",
                constraints: new { lang = @"(\w{2})|(\w{2}-\w{2})" },   // en or en-US
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
Run Code Online (Sandbox Code Playgroud)

en-US目前我的语言切换器是这样工作的,对于每种可用的语言,我获取当前的 URL 并创建带有适当语言ieru-RU等的链接

<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
        @foreach (CultureViewModel culture in Global.EnabledCultures)
        {
            <li><span class="Language dropdown-item" title="@culture.DisplayName">@Html.Raw(Url.LangSwitcher(culture.DisplayName, ViewContext.RouteData, culture.Name))</span></li>
        }
    </div>
Run Code Online (Sandbox Code Playgroud)

其中 Url.LangSwitcher 是 UrlHelper 的扩展

public static string LangSwitcher(this UrlHelper url, string name, RouteData routeData, string lang, bool isMainMenu = false)
{
    var action = (routeData.Values["action"] ?? "").ToString().ToLower();
    var controller = (routeData.Values["controller"] ?? "").ToString().ToLower();
    var requestContext = HttpContext.Current.Request.RequestContext;
    string link = "";

    // We need to create a unique URL for the current page for each of the enabled languages for this portal
    // If the lang variable is specified for current URL we need to substitute with the incoming lang variable
    //we need to duplicate the RouteData object and use the duplicate for URL creation as
    //changing the value of lang in RouteData object passed to this function changes the current culture of the request

        RouteData localValues = new RouteData();
        foreach (KeyValuePair<string, object> var in routeData.Values)
        {
            if (var.Key != "lang")
            {
                localValues.Values.Add(var.Key, var.Value);
            }
        }
    localValues.Values.Add("lang", lang);
    link = "<a href = \"" + new UrlHelper(requestContext).Action(action, controller, localValues.Values) + "\" >";


    string img = "<img src=\"/Content/images/Flags/" + lang + ".gif\" alt = \"" + lang + "\"> " + name;
    string closeTags = "</a>";

    return link + img + closeTags;
}
Run Code Online (Sandbox Code Playgroud)

因此它会获取当前的 URL 并切换出语言块并输出我们正在创建的菜单的链接。

这在遵循标准{lang}/{controller}/{action}/{id}模式的链接上运行良好

但是,我希望能够在控制器上创建带有属性的自定义链接,如下所示:

[Route("brokers/this/is/a/custom/url")]
        public ActionResult CompareBrokers(int page = 1)
        {
Run Code Online (Sandbox Code Playgroud)

所以当我尝试从这样的视图访问这条路线时:

@Url.Action("CompareBrokers", "Brokers")
Run Code Online (Sandbox Code Playgroud)

生成的URL是这样的:

https://localhost:44342/brokers/this/is/a/custom/url?lang=en-US
Run Code Online (Sandbox Code Playgroud)

我希望它是这样的

https://localhost:44342/en-US/brokers/this/is/a/custom/url
Run Code Online (Sandbox Code Playgroud)

对于我目前的设置如何实现我想要的目标,有什么建议吗?

更新放置 作为[Route("{lang}/brokers/this/is/a/custom/url")]我的属性取得了一些有限的成功,只要当前 URL 中有 lang 变量,它就会工作,所以如果我在http://site.url/en-US上,那么链接就会正确创建,但是如果我在http://site.url上,他们就不会。

我尝试在我的控制器中添加两个属性:

[Route("brokers/this/is/a/custom/url")]
[Route("{lang}/brokers/this/is/a/custom/url")]
Run Code Online (Sandbox Code Playgroud)

但它只使用第一个

更新2

按照评论中的建议我使用了该属性:

[Route("{lang=en-GB}/brokers/this/is/a/custom/url")]
Run Code Online (Sandbox Code Playgroud)

它工作得很好,我的链接生成正确,但是我需要能够适应默认本地化,而不需要 URL 中的 lang var

J.L*_*cos 6

如果将两个属性与 order 参数一起放置,则路由将首先尝试将第一个路由与 lang 参数进行匹配,如果未提供 lang 参数,它将回退到第二个路由。

[Route("{lang}/brokers/this/is/a/custom/url", Order = 1)]
[Route("brokers/this/is/a/custom/url", Order =  2)]
public ActionResult CompareBrokers(int page = 1)
{
}
Run Code Online (Sandbox Code Playgroud)

更新:要在 lang 为默认语言时使用第二条路由,您可以通过添加 actionFilter 或 controllerActivator 从路由数据中删除 lang :

if (filterContext.RouteData.Values["lang"]?.ToString() == _DefaultLanguage)
{
    filterContext.RouteData.Values.Remove("lang");
}
Run Code Online (Sandbox Code Playgroud)