ASP.NET интернационализация маршрутов (MVC)

#asp.net #asp.net-mvc #internationalization #routing

#asp.net #asp.net-mvc #интернационализация #маршруты

Вопрос:

Я искал решение для интернационализации / локализации маршрутов на ASP.NET Веб-сайт MVC. Я наткнулся на сообщение в блоге о переводе маршрутов (ASP.NET MVC и Webforms) от Мартена Баллиау. Он представил очень хорошее решение, которое отлично работает — до тех пор, пока в представлении не появится Html.RenderAction("...") .

По сути, он вводит TranslatedRoute наследование от System.Web.Routing.Route , которое затем выполняет перевод с использованием словаря с переводами на лету.

Есть идеи, почему это ведет себя по-другому при вызове Html.RenderAction("...") ? Также кажется, что ошибка возникает только в том случае, если действие, которое должно быть отображено, находится в том же контроллере.

И вот точная ошибка:

«Контроллер для path ‘/MyTranslatedControllerName’ не найден или не реализует IController».

Обновить:

Вот моя конфигурация маршрутов (взята из образца проекта Мартена, добавлены маршруты для Contact, которые являются частью, подлежащей визуализации):

     public static void RegisterRoutes(RouteCollection routes)
        {
            CultureInfo cultureEN = CultureInfo.GetCultureInfo("en-US");
            CultureInfo cultureDE = CultureInfo.GetCultureInfo("de-DE");
            CultureInfo cultureFR = CultureInfo.GetCultureInfo("fr-FR");

            DictionaryRouteValueTranslationProvider translationProvider = new DictionaryRouteValueTranslationProvider(
                new List<RouteValueTranslation> {
                    new RouteValueTranslation(cultureEN, "Home", "Home"),
                    new RouteValueTranslation(cultureEN, "About", "About"),
                    new RouteValueTranslation(cultureEN, "Contact", "Contact"),
                    new RouteValueTranslation(cultureDE, "Home", "Home"),
                    new RouteValueTranslation(cultureDE, "About", "About"),
                    new RouteValueTranslation(cultureDE, "Contact", "Kontakt"),
                    new RouteValueTranslation(cultureFR, "Home", "Demarrer"),
                    new RouteValueTranslation(cultureFR, "About", "Infos"),
                    new RouteValueTranslation(cultureFR, "Contact", "Contact")
                }
            );

            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapTranslatedRoute(
                "TranslatedRoute",
                "{controller}/{action}/{id}",
                new { controller = "Home", action = "Index", id = "" },
                new { controller = translationProvider, action = translationProvider },
                true
            );

            routes.MapRoute(
                "Default",                                              // Route name
                "{controller}/{action}/{id}",                           // URL with parameters
                new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
            );
  

Комментарии:

1. Вы можете попробовать потрясающий проект AttributeRouting , который я только что нашел! Вы можете получить это через NuGet .

Ответ №1:

Это будет зависеть от конфигурации вашего маршрута. Можете ли вы поделиться этим?

РЕДАКТИРОВАТЬ: Похоже, что метод RenderAction использует «GetVirtualPath» в маршруте для определения URL-адреса для MvcHandler. Однако это не приводит к обратному вызову метода «GetRouteData».

Существует метод обнаружения этого: RouteData.DataTokens[«ParentActionViewContext»] Проблема в том, что на этапе конвейера TranslatedRoute узнает об этом слишком поздно…

Короче говоря: я боюсь, что это невозможно из-за текущей реализации ChildActionExtensions.ActionHelper в System.Web.Mvc…

У меня действительно есть (грязный, неуважительный к самому себе) обходной путь (который вы также можете обернуть в пользовательский метод RenderAction ()): — На ваш взгляд, сделайте это:

 <%
RouteData.DataTokens.Add("GoingToRenderChildAction",
true); %> <%
Html.RenderAction("Contact", "Home");
%> <%
RouteData.DataTokens["GoingToRenderChildAction"]
= false; %>
  

Синтаксис Razor:

 @{
    ViewContext.RequestContext.RouteData.DataTokens.Add("GoingToRenderChildAction",
                                                         true);
}

@Html.Action("Action", "Controller" )

@{
    ViewContext.RequestContext.RouteData.DataTokens["GoingToRenderChildAction"]=false;
}
  

В TranslatedRoute.cs GetVirtualPath добавьте следующее в качестве первого оператора:

 if(requestContext.RouteData.DataTokens.ContainsKey("GoingToRenderChildAction") amp;amp;
(bool)requestContext.RouteData.DataTokens["GoingToRenderChildAction"] == true)
{
    return base.GetVirtualPath(requestContext, values);
}
  

Это будет работать, но может иметь нежелательные побочные эффекты.

Комментарии:

1. Я просто использовал ваш пример проекта, добавил действие Contact в HomeController , а затем выполнил Html.RenderAction("Contact") on About.aspx . Также добавлены новые new RouteValueTranslation(cultureEN, "Contact", "Contact") (также для других культур)

2. Спасибо! Итак, я подумаю о том, чтобы испортить свой код этим решением 😉 Жаль, ваш подход к локализации маршрутов был самым чистым решением, которое я когда-либо находил…

3. @maartenba: Отличное решение. Я только что обновил ваш ответ соответствующим синтаксисом Razor. Я также использую вашего поставщика карты сайта MVC: mvcsitemap.codeplex.com Вы очень помогли с этими реализациями… Спасибо!

Ответ №2:

На ваш взгляд (синтаксис Razor, VB):

 @Html.Action("Index", "Home", New With {.childAction = True})
  

Затем в TranslatedRoute.cs получаем VirtualPath в качестве первого оператора:

 if (values.ContainsKey("childAction") amp;amp;
   (bool)values["childAction"] == true)
{
  return base.GetVirtualPath(requestContext, values);
}
  

Этот способ намного проще и предназначен только для желаемого действия.