Подтвердить что ты не робот

ASP.net MVC поддержка URL с дефисами

Есть ли простой способ заставить MvcRouteHandler преобразовать все дефисы в секции действия и контроллера входящего URL-адреса, чтобы подчеркнуть, что дефисы не поддерживаются в именах методов или классов.

Это было бы так, что я мог бы поддерживать такие структуры, как sample.com/test-page/edit-details, сопоставление с Action edit_details и Controller test_pagecontroller, продолжая использовать метод MapRoute.

Я понимаю, что могу указать атрибут имени действия и поддерживать дефисы в именах контроллеров, которые вручную добавляют маршруты для достижения этого, но я ищу автоматизированный способ, чтобы сохранить ошибки при добавлении новых контроллеров и действий.

4b9b3361

Ответ 1

Я разработал решение. RequestContext внутри MvcRouteHandler содержит значения для контроллера и действия, на которых вы можете легко выполнить замену.

Public Class HyphenatedRouteHandler
    Inherits MvcRouteHandler

    Protected Overrides Function GetHttpHandler(ByVal requestContext As System.Web.Routing.RequestContext) As System.Web.IHttpHandler
        requestContext.RouteData.Values("controller") = requestContext.RouteData.Values("controller").ToString.Replace("-", "_")
        requestContext.RouteData.Values("action") = requestContext.RouteData.Values("action").ToString.Replace("-", "_")
        Return MyBase.GetHttpHandler(requestContext)
    End Function

End Class

Затем вам нужно заменить route.MapRoute эквивалентными маршрутами. Добавьте указатель нового маршрута. Это необходимо, так как MapRoute не позволяет указать настраиваемый обработчик маршрута.

routes.Add(New Route("{controller}/{action}/{id}", New RouteValueDictionary(New With {.controller = "Home", .action = "Index", .id = ""}), New HyphenatedRouteHandler()))

Ответ 2

С# версия John Post для тех, кто предпочел бы ее: версия С# и VB в моем блоге

public class HyphenatedRouteHandler : MvcRouteHandler{
        protected override IHttpHandler  GetHttpHandler(RequestContext requestContext)
        {
            requestContext.RouteData.Values["controller"] = requestContext.RouteData.Values["controller"].ToString().Replace("-", "_");
            requestContext.RouteData.Values["action"] = requestContext.RouteData.Values["action"].ToString().Replace("-", "_");
            return base.GetHttpHandler(requestContext);
        }
    }

... и новый маршрут:

routes.Add(
            new Route("{controller}/{action}/{id}", 
                new RouteValueDictionary(
                    new { controller = "Default", action = "Index", id = "" }),
                    new HyphenatedRouteHandler())
        );

Вы также можете использовать следующий метод, но помните, что вам нужно будет назвать представление My-Action, которое может раздражать, если вам нравится позволять визуальной студии автоматически генерировать ваши файлы вида.

[ActionName("My-Action")]
public ActionResult MyAction() {
    return View();
}

Ответ 3

Все, что вам действительно нужно сделать в этом случае, это назвать ваши представления с помощью дефиса, поскольку вы хотите, чтобы он отображался в URL-адресе, удалите дефисы в вашем контроллере, а затем добавьте атрибут ActionName, в котором есть дефисы. Нет необходимости иметь подчеркивания вообще.

У вас есть представление под названием edit-details.aspx

И иметь такой контроллер:

[ActionName("edit-details")]
public ActionResult EditDetails(int id)
{
    // your code
}

Ответ 4

Я понимаю, что это довольно старый вопрос, но для меня это всего лишь половина истории принятия URL-адреса с дефисами в них, другая половина генерирует эти URL-адреса, сохраняя возможность использования Html.ActionLink и других помощников в MVC Framework, я решил это, создав собственный класс маршрутов, похожий, вот код, если он помогает любому, кто приходит сюда из поиска Google. Он также включает нижнюю оболочку URL-адреса.

public class SeoFriendlyRoute : Route
{
     // constructor overrides from Route go here, there is 4 of them

     public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
     {
          var path = base.GetVirtualPath(requestContext, values);

          if (path != null)
          {
              var indexes = new List<int>();
              var charArray = path.VirtualPath.Split('?')[0].ToCharArray();
              for (int index = 0; index < charArray.Length; index++)
              {
                  var c = charArray[index];
                  if (index > 0 && char.IsUpper(c) && charArray[index - 1] != '/')
                      indexes.Add(index);
              }

              indexes.Reverse();
              indexes.Remove(0);
              foreach (var index in indexes)
                  path.VirtualPath = path.VirtualPath.Insert(index, "-");

              path.VirtualPath = path.VirtualPath.ToLowerInvariant();
          }

          return path;
     }
}

то при добавлении маршрутов вы можете либо создать расширения RouteCollection, либо использовать только следующие объявления глобальной маршрутизации

routes.Add(
        new SeoFriendlyRoute("{controller}/{action}/{id}", 
            new RouteValueDictionary(
                new { controller = "Default", action = "Index", id = "" }),
                new HyphenatedRouteHandler())
    );

Ответ 5

Спасибо dsteuernol за этот ответ - именно то, что я искал. Однако я обнаружил, что мне нужно улучшить HyphenatedRouteHandler, чтобы охватить сценарий, в котором Контроллер или Область подразумевались с текущей страницы. Например, используя @Html.ActionLink( "Моя ссылка", "Индекс" )

Я изменил метод GetHttpHandler на следующее:

public class HyphenatedRouteHandler : MvcRouteHandler
    {
        /// <summary>
        /// Returns the HTTP handler by using the specified HTTP context.
        /// </summary>
        /// <param name="requestContext">The request context.</param>
        /// <returns>
        /// The HTTP handler.
        /// </returns>
        protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
        {

            requestContext.RouteData.Values["controller"] = ReFormatString(requestContext.RouteData.Values["controller"].ToString());
            requestContext.RouteData.Values["action"] = ReFormatString(requestContext.RouteData.Values["action"].ToString());

            // is there an area
            if (requestContext.RouteData.DataTokens.ContainsKey("area"))
            {
                requestContext.RouteData.DataTokens["area"] = ReFormatString(requestContext.RouteData.DataTokens["area"].ToString());
            }

            return base.GetHttpHandler(requestContext);
        }


        private string ReFormatString(string hyphenedString)
        {
            // lets put capitals back in

            // change dashes to spaces
            hyphenedString = hyphenedString.Replace("-", " ");

            // change to title case
            hyphenedString = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(hyphenedString);

            // remove spaces
            hyphenedString = hyphenedString.Replace(" ", "");

            return hyphenedString;
        }
    }

Возвращение столиц означало, что предполагаемый контроллер или область были затем переведены правильно.

Ответ 6

Я разработал библиотеку с открытым исходным кодом NuGet для этой проблемы, которая неявно преобразует EveryMvc/Url в каждый-mvc/url.

Пунктирные URL-адреса гораздо более дружественны к SEO и их легче читать. (Подробнее о моем сообщении в блоге)

Пакет NuGet: https://www.nuget.org/packages/LowercaseDashedRoute/

Чтобы установить его, просто откройте окно NuGet в Visual Studio, щелкнув правой кнопкой мыши Project и выбрав NuGet Package Manager, а на вкладке "Онлайн" введите "Строчный штрихованный маршрут", и он должен появиться.

В качестве альтернативы вы можете запустить этот код в консоли диспетчера пакетов:

Install-Package LowercaseDashedRoute

После этого вы должны открыть App_Start/RouteConfig.cs и прокомментировать существующий route.MapRoute(...) и добавить вместо этого:

routes.Add(new LowercaseDashedRoute("{controller}/{action}/{id}",
  new RouteValueDictionary(
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }),
    new DashedRouteHandler()
  )
);

Что это. Все URL-адреса строчные, пунктирные и конвертируются неявно, если вы ничего не делаете.

Open Source Project Url: https://github.com/AtaS/lowercase-dashed-route

Ответ 7

Не знаю способа без написания карты для каждого URL:

routes.MapRoute("EditDetails", "test-page/edit-details/{id}", new { controller = "test_page", action = "edit_details" });

Ответ 8

Если вы обновите проект до MVC5, вы можете использовать маршрутизацию атрибутов.

[Route("controller/my-action")]
public ActionResult MyAction() {
    return View();
}

Я предпочитаю этот подход к принятому решению, которое оставляет вас с подчеркиваниями в именах действий контроллера и просмотра имен файлов, а также дефисами в ваших помощниках Url.Action. Я предпочитаю согласованность и не помню, как преобразуются имена.

Ответ 9

В MVC 5.2.7 вы можете просто указать, используя атрибут

ActionName

[ActionName("Import-Export")]
public ActionResult ImportExport()
{
    return View();
}

Затем назовите вид

Import-Export.cshtml

Ссылка будет:

@Html.ActionLink("Import and Export", "Import-Export", "Services")

Который имеет форму:

@Html.ActionLink("LinkName", "ActionName", "ControllerName")