【问题标题】:Enforce Hyphens in .NET MVC 4.0 URL Structure在 .NET MVC 4.0 URL 结构中强制使用连字符
【发布时间】:2012-01-17 19:09:51
【问题描述】:

我正在专门寻找一种自动连接 CamelCase 操作和视图的方法。也就是说,我希望我不必真正重命名我的视图或为站点中的每个 ActionResult 添加装饰器。

到目前为止,我一直在使用routes.MapRouteLowercase,如图here。这对于 URL 结构的小写部分非常有效,但对于连字符则无效。所以我最近开始使用Canonicalize(通过 NuGet 安装),但它还没有任何连字符。

我在尝试...

routes.Canonicalize().NoWww().Pattern("([a-z0-9])([A-Z])", "$1-$2").Lowercase().NoTrailingSlash();

我的正则表达式肯定会按照我想要的方式正确地重构 URL,但当然,这些 URL 没有被识别。例如,该文件仍然是ChangePassword.cshtml,所以/account/change-password 不会指向它。

顺便说一句,我对 .NET MVC 还是有点生疏。我已经有几年没用过了,从 v2.0 开始就没有了。

【问题讨论】:

  • 看起来我错过了 1 分钟的赏金期。请在授予它之前考虑我的答案......路线处理程序虽然很聪明,但错过了问题的重点,并增加了不必要的复杂性。感谢您的考虑

标签: asp.net-mvc-routing lowercase hyphenation asp.net-mvc-4


【解决方案1】:

这可能有点混乱,但是如果您创建了自定义 HttpHandlerRouteHandler,那么这应该可以防止您必须重命名所有视图和操作。您的处理程序可以从请求的操作中删除连字符,这会将“更改密码”更改为更改密码,从而呈现 ChangePassword 操作。

为了简洁起见,代码被缩短了,但重要的部分都在那里。

public void ProcessRequest(HttpContext context)
{
    string controllerId = this.requestContext.RouteData.GetRequiredString("controller");
    string view = this.requestContext.RouteData.GetRequiredString("action");

    view = view.Replace("-", "");
    this.requestContext.RouteData.Values["action"] = view;

    IController controller = null;
    IControllerFactory factory = null;

    try
    {
        factory = ControllerBuilder.Current.GetControllerFactory();
        controller = factory.CreateController(this.requestContext, controllerId);

        if (controller != null)
        {
            controller.Execute(this.requestContext);
        }
    }
    finally
    {
        factory.ReleaseController(controller);
    }
}

我不知道我是否以最好的方式实现它,这或多或少取自我遇到的第一个sample。我自己测试了代码,所以这确实呈现了正确的操作/视图,并且应该可以解决问题。

【讨论】:

    【解决方案2】:

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

    大写 url 存在问题,因为 cookie 路径区分大小写,大多数互联网实际上是区分大小写的,而 Microsoft 技术将 url 视为不区分大小写。 (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

    【讨论】:

      【解决方案3】:

      您是否尝试过使用 URL 重写包?我认为这正是您要寻找的。​​p>

      http://www.iis.net/download/urlrewrite

      Hanselman 有一个很好的例子E:

      http://www.hanselman.com/blog/ASPNETMVCAndTheNewIIS7RewriteModule.aspx

      另外,为什么不下载 ReSharper 或 CodeRush 之类的东西,并用它来重构 Action 和 Route 名称?这真的简单,而且非常安全。

      花费一小时的重构时间来修复路由/操作命名约定比您已经花费的所有时间尝试更改路由约定以满足您的需求所花费的时间要少得多。

      只是一个想法。

      【讨论】:

      • 我确实使用了 ReSharper,但我没有任何代码可以重构。我正在对基础 MVC 4.0 项目进行概念验证。我也玩过重写模块,问题是悬停链接仍然大写。这是一个问题,因为搜索引擎会看到 2 个指向同一页面的不同链接。在进行重写之前,它必须是小写的。
      • 在此上下文中重构意味着,只需重命名您的 Actions/Methods... 在 R# 中它只是 Ctr+R, R 并且会弹出一个小家伙让您输入新名称,并带有一点点注意力,您就可以在整个应用程序中清理它而不会破坏任何东西。我只会在之后使用 URL 重写。最好的办法是遵循 MVC 约定,因为它是一个基于约定的框架
      • @one.beat.consumer MVC 是基于约定的,是的,但是约定只在现实世界中带你走这么远。 MVC 最好的地方在于它的灵活性。它充满了可扩展性点,以弥补框架中的任何缺陷。如果默认情况下它不能按照您希望的方式工作 - 然后扩展它。我为他的问题提供了一个可行的、合理的解决方案(而不是你提供的“改变你想做的方式”的解决方案)。在我看来,不值得投反对票。
      • @hawkke 当然。我不想在这里辩论,只是指出有时不值得努力与公约作斗争。除非绝对需要在包含下划线的 CamelCase 命名中使用 Action 名称,否则当他已经拥有可以帮助他完全避免该问题的许可工具时,更改 RouteHandler 和其他对象似乎很愚蠢。 “榨汁值得”是我的一个系统管理员经常说的......除了要管理更多代码之外,他从编辑路由处理程序中获得了什么?感谢您的评论,您的回答还是不错的。
      【解决方案4】:

      我在上面接受的答案中尝试了解决方案:使用 Canonicalize Pattern url 策略,然后还添加了一个自定义 IRouteHandler,然后返回一个自定义 IHttpHandler。它大部分起作用了。这是我发现的一个警告:

      使用典型的{controller}/{action}/{id}默认路由,一个名为CatalogController的控制器,里面有一个action方法如下:

      ActionResult QuickSelect(string id){ /*do some things, access the 'id' parameter*/ }
      

      我注意到对“/catalog/quick-select/1234”的请求运行良好,但是对 /catalog/quick-select?id=1234 的请求是 500'ing,因为一旦由于 @ 调用了操作方法987654325@,id 参数在 action 方法中为空。

      我不知道为什么会这样,但是这种行为就像 MVC 在模型绑定期间没有查看查询字符串中的值一样。因此,在接受的答案中,关于 ProcessRequest 实现的一些事情是搞砸了正常的模型绑定过程,或者至少是查询字符串值提供程序。

      这是一个交易破坏者,所以我看了一下默认的 MVC IHttpHandler(耶开源!):http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/MvcHandler.cs

      我不会假装我已经完全理解了它,但很明显,它在实现ProcessRequest 时所做的比在接受的答案中所做的要多得多。

      所以,如果我们真正需要做的就是从传入的路由数据中去除破折号,以便 MVC 可以找到我们的控制器/动作,为什么我们需要实现一个完整的臭名昭著的 IHttpHandler?我们没有!只需撕掉DashedRouteHandlerGetHttpHandler 方法中的破折号,然后将requestContext 传递给开箱即用的MvcHandler,这样它就可以执行252 行魔术,而您的路由处理程序不必返回一个二流的 IHttpHandler。

      tl:dr; - 这是我所做的:

      public class DashedRouteHandler : IRouteHandler
          {
              public IHttpHandler GetHttpHandler(RequestContext requestContext)
              {
                  requestContext.RouteData.Values["action"] = requestContext.RouteData.GetRequiredString("action").Replace("-", "");
                  requestContext.RouteData.Values["controller"] = requestContext.RouteData.GetRequiredString("controller").Replace("-", "");
      
                  return new MvcHandler(requestContext);
              }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-03-02
        • 2018-02-06
        • 1970-01-01
        • 1970-01-01
        • 2012-06-01
        • 2011-06-03
        • 2011-07-13
        • 2011-11-28
        相关资源
        最近更新 更多