ASP.net MVC支持带有连字符的URL

时间:2010-01-15 10:45:41

标签: asp.net-mvc url url-routing seo

是否有一种简单的方法可以让MvcRouteHandler将传入URL的操作和控制器部分中的所有连字符转换为下划线,因为方法或类名称不支持连字符。

这样我就可以支持像sample.com/test-page/edit-details这样的结构映射到Action edit_details和Controller test_pagecontroller,同时继续使用MapRoute方法。

据我所知,我可以在控制器名称中指定一个操作名称属性并支持连字符,这些连字符会手动添加路由以实现此目的,但我正在寻找一种自动方式,以便在添加新控制器和操作时节省错误。

9 个答案:

答案 0 :(得分:32)

对于喜欢它的人来说,John的帖子的C#版本: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())
        );

您也可以使用以下方法,但请记住,如果您希望让visual studio自动生成您的视图文件,则需要将视图命名为My-Action,这可能很烦人。

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

答案 1 :(得分:18)

我找到了解决方案。 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.Add替换routes.MapRoute,指定新的路由处理程序。这是必需的,因为MapRoute不允许您指定自定义路由处理程序。

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

答案 2 :(得分:14)

在这种情况下,您真正​​需要做的就是使用连字符命名您的视图,因为您希望它出现在URL中,删除控制器中的连字符,然后添加一个将连字符放回其中的ActionName属性。根本不需要下划线。

有一个名为 edit-details.aspx

的视图

并拥有一个这样的控制器:

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

答案 3 :(得分:9)

我意识到这是一个相当古老的问题,但对我来说这只是接受带有连字符的url的故事的一半,另一半是生成这些网址,同时仍然可以使用Html.ActionLink和其他帮助MVC框架,我通过创建类似的自定义路由类解决了这个问题,这里的代码是为了帮助任何人从谷歌搜索来到这里。它还包括网址的下部外壳。

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())
    );

答案 4 :(得分:2)

感谢dsteuernol这个答案 - 正是我所寻找的。但是我发现我需要增强HyphenatedRouteHandler来覆盖从当前页面隐含Controller或Area的场景。例如,使用@ 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;
        }
    }

重新放入大写字母意味着隐含的控制器或区域被正确连字。

答案 5 :(得分:1)

我为此问题开发了一个开源 NuGet库,它隐式地将EveryMvc / Url转换为每个mvc / url。

虚线网址更加友好,更易于阅读。 (More on my blog post

NuGet套餐:https://www.nuget.org/packages/LowercaseDashedRoute/

要安装它,只需在Visual Studio中打开NuGet窗口,右键单击Project并选择NuGet Package Manager,然后在“Online”选项卡上键入“Lowercase Dashed Route”,它就会弹出。

或者,您可以在程序包管理器控制台中运行此代码

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()
  )
);

就是这样。所有网址都是小写,虚线和隐式转换,而不需要你做更多的事情。

开源项目网址:https://github.com/AtaS/lowercase-dashed-route

答案 6 :(得分:0)

如果没有为每个网址编写地图,请不要知道:

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

答案 7 :(得分:0)

如果将项目升级到MVC5,则可以使用属性路由。

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

我更喜欢这种方法来接受已接受的解决方案,它会在您的控制器操作名称和视图文件名中留下下划线,并在您的视图的Url.Action助手中显示连字符。我更喜欢一致性,而不必记住名称的转换方式。

答案 8 :(得分:0)

在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")