Пользовательская маршрутизация с атрибутом языка в URL для сайта MVC .net - PullRequest
0 голосов
/ 02 мая 2018

У меня есть сайт, который требует локализации на несколько разных языков. Чтобы достичь этого, я следовал учебнику здесь 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 и создаю ссылку с соответствующим языковым фрагментом, т.е. en-US или ru-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, отключает языковой фрагмент и выводит ссылку для меню, которое мы создаем.

Все это прекрасно работает на ссылках, которые следуют стандартному шаблону {lang}/{controller}/{action}/{id}

однако я хочу иметь возможность создавать пользовательские ссылки с атрибутами на контроллерах следующим образом:

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

поэтому, когда я пытаюсь получить доступ к этому маршруту из вида, подобного так:

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

сгенерированный URL выглядит следующим образом:

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

где я хочу, чтобы это было так

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

Какой-нибудь совет, как мне добиться того, чего я хочу, с моей текущей настройкой?

UPDATE если поставить [Route("{lang}/brokers/this/is/a/custom/url")], поскольку мой атрибут имеет ограниченный успех, он будет работать до тех пор, пока в текущем URL есть переменная lang, поэтому, если я использую http://site.url/en-US, тогда ссылки создаются правильно, но если я на http://site.url нет.

Я попытался поместить 2 атрибута в мой контроллер:

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

но он просто использует первый

ОБНОВЛЕНИЕ 2

Следуя советам в комментариях, я использовал атрибут:

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

и он работает отлично, мои ссылки генерируются правильно, однако мне нужно иметь возможность разместить локализацию по умолчанию без lang var в URL

1 Ответ

0 голосов
/ 04 мая 2018

Если вы зададите два атрибута с параметром порядка, маршрутизация сначала попытается сопоставить первый маршрут с параметром 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 является языком по умолчанию, вы можете удалить lang из routedata, добавив в свой actionFilter или controllerActivator:

if (filterContext.RouteData.Values["lang"]?.ToString() == _DefaultLanguage)
{
    filterContext.RouteData.Values.Remove("lang");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...