Custom routing with language attribute in URL for MVC .net site

大城市里の小女人 提交于 2019-12-23 22:24:18

问题


I have a site which requires localization into a number of different languages. To achieve this I followed the tutorial here https://www.ryadel.com/en/setup-a-multi-language-website-using-asp-net-mvc/ In my route config I have :

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 }
            );

Currently my language switcher works like this, for every available language I take the current URL and create a link with the appropriate language slug i.e. en-US or ru-RU etc

<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>

Where Url.LangSwitcher is an Extension of 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;
}

so it takes the current URL and switches out the language slug and outputs a link for the menu we are creating.

This all works fine on links that follow the standard {lang}/{controller}/{action}/{id} pattern

however, I want to be able to create custom links with attributes on the controllers like so:

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

so when I try to access this route from a view like so:

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

the URL that is generated is like this:

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

where I want it to be like this

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

Any advice on how I can achieve what I want given my current set up?

UPDATE putting [Route("{lang}/brokers/this/is/a/custom/url")] as my attribute has some limited success, it will work as long as there is a lang variable in the current URL, so if I am on http://site.url/en-US then the links get created correctly, but if I am on http://site.url they do not.

Ive tried putting 2 attributes in my controller:

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

but it just uses the first one

UPDATE 2

Following advice in the comments I used the attribute:

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

and it works perfectly, my links get generated correctly, however I need to be able to accommodate the default localization without the lang var in the URL


回答1:


If you put two attributes with the order paramter, the routing will first try to match the first route with the lang parameter, and if the lang parameter is not supplied it will fallback on the second route.

[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)
{
}

UPDATE : To use the 2nd route when lang is the default language you could remove lang from the routedata by adding in your actionFilter or controllerActivator :

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



回答2:


This is what worked for me one month later after i gave up and went to use normal routing / route config files, Please note that I'm using Areas and the area name here is "Merchant"

Normal link :

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

To open it as a Custom link like:

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 file

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 file

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" }
            );
        }
    }
}


来源:https://stackoverflow.com/questions/50129934/custom-routing-with-language-attribute-in-url-for-mvc-net-site

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!