代码之家  ›  专栏  ›  技术社区  ›  John

ASP.NET MVC支持带连字符的URL

  •  30
  • John  · 技术社区  · 16 年前

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

    这样我就可以支持sample.com/test-page/edit-details映射到action edit_details和controller test_page controller等结构,同时继续使用maproute方法。

    我知道我可以指定一个action name属性,并支持控制器名称中的连字符,通过手动添加路由来实现这一点,但是我正在寻找一种自动化的方法,以便在添加新的控制器和操作时保存错误。

    8 回复  |  直到 8 年前
        1
  •  31
  •   Andrew    15 年前

    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自动生成视图文件,这可能会很烦人。

    [ActionName("My-Action")]
    public ActionResult MyAction() {
        return View();
    }
    
        2
  •  18
  •   John    16 年前

    我想出了一个解决办法。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。添加指定新的路由处理程序。这是必需的,因为MapRoute不允许您指定自定义路由处理程序。

    routes.Add(New Route("{controller}/{action}/{id}", New RouteValueDictionary(New With {.controller = "Home", .action = "Index", .id = ""}), New HyphenatedRouteHandler()))
    
        3
  •  14
  •   Chris Conway    15 年前

    在这种情况下,您真正需要做的就是使用希望在URL中显示的连字符为视图命名,删除控制器中的连字符,然后添加一个actionname属性,该属性中包含连字符。根本不需要下划线。

    调用视图 编辑详细信息.aspx

    有一个这样的控制器:

    [ActionName("edit-details")]
    public ActionResult EditDetails(int id)
    {
        // your code
    }
    
        4
  •  9
  •   dsteuernol    14 年前

    我意识到这是一个很古老的问题,但对我来说,这只是接受带有连字符的URL的一半,另一半生成这些URL,同时仍然能够在MVC框架中使用html.actionlink和其他助手,我通过创建类似的自定义路由类来解决这个问题,这里是代码,以防它帮助任何人来这里是谷歌搜索。它还包括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
  •  2
  •   Sylvia    13 年前

    感谢dsteuernol给我这个答案——正是我想要的。然而,我发现我需要增强hyphenateroutehandler来覆盖当前页面中暗示控制器或区域的场景。例如,使用@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
  •  1
  •   Ata S.    13 年前

    我开发了一个开源软件 努吉特图书馆 对于这个问题,它隐式地将every mvc/url转换为每个mvc/url。

    虚URL对SEO更友好,更容易阅读。( More on my blog post )

    NuGet Package: https://www.nuget.org/packages/LowercaseDashedRoute/

    要安装它,只需右键单击项目并选择Nuget Package Manager,然后在“联机”选项卡类型“小写虚线路由”上打开Visual Studio中的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都是小写的、虚线的,并且是隐式转换的,不需要您做任何其他操作。

    开放源代码项目URL: https://github.com/AtaS/lowercase-dashed-route

        7
  •  0
  •   Paul Hiles    16 年前

    不为每个URL编写映射就不知道方法:

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

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

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

    与公认的解决方案相比,我更喜欢这种方法,它在控制器操作名和视图文件名中留下下划线,并在视图的url.action助手中留下连字符。我更喜欢一致性,不必记住名称是如何转换的。