ASP.net MVC 对带有连字符的 URL 的支持
Posted
技术标签:
【中文标题】ASP.net MVC 对带有连字符的 URL 的支持【英文标题】:ASP.net MVC support for URL's with hyphens 【发布时间】:2011-01-05 11:12:27 【问题描述】:是否有一种简单的方法可以让 MvcRouteHandler 将传入 URL 的操作和控制器部分中的所有连字符转换为下划线,因为连字符在方法或类名称中不受支持。
这样我就可以在继续使用 MapRoute 方法的同时支持诸如 sample.com/test-page/edit-details 映射到 Action edit_details 和 Controller test_pagecontroller 之类的结构。
我知道我可以指定一个动作名称属性并支持控制器名称中的连字符,这些连字符可以手动添加路由来实现这一点,但是我正在寻找一种自动化方式,以便在添加新控制器和动作时避免错误。
【问题讨论】:
连字符在 URL 中被视为对用户更友好。下划线与带下划线的链接冲突。 你可以看看这篇文章,展示如何实现custom MvcRouteHandler。 Asp.Net MVC: How do I enable dashes in my urls?的可能重复 任何来自 Google 搜索的人都可以查看 @dsteuernol 的答案,因为它建立在之前的答案之上,而 IMO 是我见过的所有解决方案中最强大的。 对于 ASP.NET Core -> ***.com/questions/53022924/… 【参考方案1】:C# 版本的 John's Post 适合任何喜欢它的人:C# and VB version on my blog
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();
【讨论】:
这很好用...但是要注意controller = "Default"
。在注意到它并将其更改为“Home”之前,我收到了几次 404。
你会如何使用@html.Actionlink 来指向连字符的url? @Html.ActionLink("Test", "Action", "ControllerName-Hyphen") 在上述情况下,actionlink 不知道如何处理连字符,我是否必须创建另一个扩展名,将“-”替换为“” ?我希望生成的网址中包含连字符【参考方案2】:
我已经找到了解决方案。 MvcRouteHandler 中的 requestContext 包含控制器和操作的值,您可以对其进行简单的替换。
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
然后,您只需将 routes.MapRoute 替换为等效的 routes.Add 以指定新的路由处理程序。这是必需的,因为 MapRoute 不允许您指定自定义路由处理程序。
routes.Add(New Route("controller/action/id", New RouteValueDictionary(New With .controller = "Home", .action = "Index", .id = ""), New HyphenatedRouteHandler()))
【讨论】:
你会如何使用@Html.Actionlink 来指向连字符的url? @Html.ActionLink("Test", "Action", "ControllerName-Hyphen") 在上述情况下,actionlink 不知道如何处理连字符,我是否必须创建另一个扩展名,将“-”替换为“” ?我希望生成的网址中包含连字符 用连字符写你的动作链接,当 MVC 查找路由时,它将使用 HyphenatedRouteHandler 来解析它并生成完整的 URL。 好吧,看起来它运行良好,我只是从 resharper 得到一个语法检查问题,因为它不知道映射谢谢【参考方案3】:在这种情况下,您真正需要做的就是使用连字符为视图命名,因为您希望它出现在 URL 中,删除控制器中的连字符,然后添加一个包含连字符的 ActionName 属性。根本不需要下划线。
有一个名为 edit-details.aspx
的视图并且有一个这样的控制器:
[ActionName("edit-details")]
public ActionResult EditDetails(int id)
// your code
【讨论】:
这适用于动作,但不适用于控制器,至少在 MVC 1 中无效【参考方案4】:我意识到这是一个相当老的问题,但对我来说,这只是接受带有连字符的 url 的故事的一半,另一半是生成这些 url,同时仍然能够使用 Html.ActionLink 和其他帮助程序MVC 框架,我通过创建一个类似的自定义路由类解决了这个问题,这里是代码,以防它帮助任何从谷歌搜索来到这里的人。它还包括 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())
);
【讨论】:
这正是我想要的。 以上答案只是门票。十分感谢。我想提请注意 Sylvia J 的重要补充(目前如下)【参考方案5】:感谢 dsteuernol 的回答——正是我想要的。但是我发现我需要增强 HyphenatedRouteHandler 以涵盖当前页面隐含 Controller 或 Area 的场景。例如使用@Html.ActionLink("My Link", "Index")
我将 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 转换为 every-mvc/url。
虚线网址对 SEO 更友好且更易于阅读。 (More on my blog post)
NuGet 包:https://www.nuget.org/packages/LowercaseDashedRoute/
要安装它,只需在 Visual Studio 中打开 NuGet 窗口,方法是右键单击项目并选择 NuGet 包管理器,然后在“在线”选项卡上键入“小写虚线”,它应该会弹出。
或者,您可以在包管理器控制台中运行此代码:
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 都是小写的、破折号的,并且无需您做任何其他操作即可隐式转换。
开源项目网址: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("Import-Export")]
public ActionResult ImportExport()
return View();
然后给视图命名
导入-导出.cshtml
链接将是:
@Html.ActionLink("Import and Export", "Import-Export", "Services")
形式如下:
@Html.ActionLink("LinkName", "ActionName", "ControllerName")
【讨论】:
以上是关于ASP.net MVC 对带有连字符的 URL 的支持的主要内容,如果未能解决你的问题,请参考以下文章
SEO:带有和不带有破折号“/”和 ASP.NET MVC 的重复 URL
无法显示带有 asp.net mvc url.action 链接的引导对话框