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