Поддержка ASP.net MVC для URL с дефисами - PullRequest
31 голосов
/ 15 января 2010

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

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

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

Ответы [ 8 ]

32 голосов
/ 06 февраля 2010

C # версия Post's John для тех, кто предпочел бы ее: C # и версия 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, что может раздражать, если вы хотите, чтобы Visual Studio автоматически генерировал ваши файлы представления.

[ActionName("My-Action")]
public ActionResult MyAction() {
    return View();
}
18 голосов
/ 15 января 2010

Я разработал решение.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

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

routes.Add(New Route("{controller}/{action}/{id}", New RouteValueDictionary(New With {.controller = "Home", .action = "Index", .id = ""}), New HyphenatedRouteHandler()))
14 голосов
/ 11 февраля 2011

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

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

И такой контроллер:

[ActionName("edit-details")]
public ActionResult EditDetails(int id)
{
    // your code
}
9 голосов
/ 27 июня 2012

Я понимаю, что это довольно старый вопрос, но для меня это только половина истории принятия 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())
    );
2 голосов
/ 28 марта 2013

Спасибо 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;
        }
    }

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

1 голос
/ 03 августа 2013

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

Пунктирные URL-адреса намного удобнее для SEO и их легче читать. ( Больше на моем блоге )

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

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

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

Install-Package LowercaseDashedRoute

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

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

Вот и все. Все URL-адреса строчные, пунктирные и неявно преобразуются без каких-либо дополнительных действий.

URL проекта с открытым исходным кодом: https://github.com/AtaS/lowercase-dashed-route

0 голосов
/ 03 сентября 2017

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

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

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

0 голосов
/ 15 января 2010

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

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