Есть ли простой способ заставить MvcRouteHandler преобразовать все дефисы в секции действия и контроллера входящего URL-адреса, чтобы подчеркнуть, что дефисы не поддерживаются в именах методов или классов.
Это было бы так, что я мог бы поддерживать такие структуры, как sample.com/test-page/edit-details, сопоставление с Action edit_details и Controller test_pagecontroller, продолжая использовать метод MapRoute.
Я понимаю, что могу указать атрибут имени действия и поддерживать дефисы в именах контроллеров, которые вручную добавляют маршруты для достижения этого, но я ищу автоматизированный способ, чтобы сохранить ошибки при добавлении новых контроллеров и действий.
Ответ 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")