【问题标题】:Custom routing with language attribute in URL for MVC .net siteMVC .net 站点的 URL 中具有语言属性的自定义路由
【发布时间】:2018-10-12 06:51:11
【问题描述】:

我有一个需要本地化为多种不同语言的网站。 为了实现这一点,我按照教程here 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 }
            );

目前我的语言切换器是这样工作的,对于每种可用语言,我都会使用当前 URL 并使用适当的语言 slug 创建一个链接,即 en-USru-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>

其中 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;
}

所以它获取当前 URL 并切换语言 slug 并为我们正在创建的菜单输出一个链接。

这一切都适用于遵循标准 {lang}/{controller}/{action}/{id} 模式的链接

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

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

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

@Url.Action("CompareBrokers", "Brokers")

生成的网址是这样的:

https://localhost:44342/brokers/this/is/a/custom/url?lang=en-US

我希望它是这样的

https://localhost:44342/en-US/brokers/this/is/a/custom/url

对于我目前的设置如何实现我想要的任何建议?

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

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

[Route("brokers/this/is/a/custom/url")]
[Route("{lang}/brokers/this/is/a/custom/url")]

但它只使用第一个

更新 2

在我使用该属性的 cmets 中遵循建议:

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

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

【问题讨论】:

  • 您是否尝试过使用属性 [Route("{lang}/brokers/this/is/a/custom/url")] ?
  • 实际上,是的,但只有当我在 URL 中有 slug 的语言部分时,我想知道如何在没有 slug 的情况下让它工作,这样我就不必提供 if for默认语言(英语)如果我尝试放置 2 条路线,一条带一条不带 lang slug,那么它默认为第一个
  • 您将使用属性 [Route("{lang=en-US}/brokers/this/is/a/custom/url")] 但您必须硬编码默认语言每条自定义路线
  • 我不能这样做,因为其中一项规定是默认本地化在 URL 中没有 lang var
  • 尝试使用 [Route("{lang}/brokers/this/is/a/custom/url", Order = 1)] [Route("brokers/this/is/a/custom/ url", Order = 2)] 这样路由器首先会尝试用 {lang} 匹配路由,如果没有提供 lang 参数,它会回退到没有 lang 的路由

标签: .net asp.net-mvc routes localization


【解决方案1】:

在我放弃并使用普通路由/路由配置文件一个月后,这对我有用,请注意我使用的是区域,这里的区域名称是“Merchant”

普通链接:

https://localhost:44364/En/Merchant/Financial/TransactionDetails/55

将其作为自定义链接打开,例如:

https://localhost:44364/En/Merchant/Financial/Transactions/Transaction/Details/55

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    
    namespace GHLogistics.Areas.Merchant.Controllers
    {
        [RouteArea("{lang}")]
        [RoutePrefix("Merchant")]
        public class FinancialController : MerchantBaseController
        {
            [Route("Financial/Transactions/Transaction/Details/{Id}")]
            public ActionResult TransactionDetails(long Id)
            {
                return Content("TransactionDetails" + " " + Id.ToString());

                // or
                //pass relative path of view file, pass model
               //return View("~/Areas/Merchant/Views/Financial/TransactionDetails.cshtml",transactions);
            }
        }
    }

MerchantAreaRegistration.cs 文件

context.MapRoute(
"Merchant_default",
url: "{lang}/Merchant/{controller}/{action}/{id}",
constraints: new { lang = @"(\w{2})|(\w{2}-\w{2})" },
defaults: new { lang = "en", controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "GHLogistics.Areas.Merchant.Controllers" }
);

RouteConfig.cs 文件

namespace GHLogistics
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.MapMvcAttributeRoutes();
            AreaRegistration.RegisterAllAreas();

            routes.MapRoute(
                name: "Default",
                url: "{lang}/{controller}/{action}/{id}",
                constraints: new { lang = @"(\w{2})|(\w{2}-\w{2})" },
                defaults: new { lang = "en", controller = "Home", action = "Index", id = UrlParameter.Optional },
                namespaces: new[] { "GHLogistics.Controllers" }
            );
        }
    }
}

【讨论】:

    【解决方案2】:

    如果您将两个属性与 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)
    {
    }
    

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

    if (filterContext.RouteData.Values["lang"]?.ToString() == _DefaultLanguage)
    {
        filterContext.RouteData.Values.Remove("lang");
    }
    

    【讨论】:

    • 只剩下一个小问题,我怎样才能让它在语言非默认时选择顶部的语言,而在默认语言时选择底部的语言,以便它不包含'网址中的 en-GB' var
    • 实现这一目标的一种方法是在语言为默认语言时从 routeData 中删除 lang。
    猜你喜欢
    • 2016-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-11
    • 2016-09-11
    • 1970-01-01
    • 1970-01-01
    • 2013-12-11
    相关资源
    最近更新 更多