在 .NET MVC 4.0 URL 结构中强制使用连字符

发布于 2024-12-20 15:25:04 字数 755 浏览 3 评论 0原文

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

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

我正在尝试...

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

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

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

I'm looking specifically for a way to automatically hyphenate CamelCase actions and views. That is, I'm hoping I don't have to actually rename my views or add decorators to every ActionResult in the site.

So far, I've been using routes.MapRouteLowercase, as shown here. That works pretty well for the lowercase aspect of URL structure, but not hyphens. So I recently started playing with Canonicalize (install via NuGet), but it also doesn't have anything for hyphens yet.

I was trying...

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

My regular expression definitely works the way I want it to as far as restructuring the URL properly, but those URLs aren't identified, of course. The file is still ChangePassword.cshtml, for example, so /account/change-password isn't going to point to that.

BTW, I'm still a bit rusty with .NET MVC. I haven't used it for a couple years and not since v2.0.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

囍笑 2024-12-27 15:25:04

这可能有点混乱,但是如果您创建了自定义 HttpHandler RouteHandler 那么应该防止您不必重新命名您所有的观点和行为。您的处理程序可以从请求的操作中删除连字符,这会将“change-password”更改为changepassword,从而呈现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);
    }
}

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

This might be a tad bit messy, but if you created a custom HttpHandler and RouteHandler then that should prevent you from having to rename all of your views and actions. Your handler could strip the hyphen from the requested action, which would change "change-password" to changepassword, rendering the ChangePassword action.

The code is shortened for brevity, but the important bits are there.

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

I don't know if I implemented it the best way or not, that's just more or less taken from the first sample I came across. I tested the code myself so this does render the correct action/view and should do the trick.

留一抹残留的笑 2024-12-27 15:25:04

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

大写 url 是有问题的,因为 cookie 路径区分大小写,大多数互联网实际上是区分大小写的,而 Microsoft 技术将 url 视为不区分大小写。 (更多内容请参阅我的博客文章

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

要安装它,只需在 Visual Studio 中打开 NuGet 窗口即可右键单击项目并选择 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()
  )
);

就是这样。所有 url 均为小写、虚线,并且隐式转换,无需您执行任何其他操作。

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

I've developed an open source NuGet library for this problem which implicitly converts EveryMvc/Url to every-mvc/url.

Uppercase urls are problematic because cookie paths are case-sensitive, most of the internet is actually case-sensitive while Microsoft technologies treats urls as case-insensitive. (More on my blog post)

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

To install it, simply open the NuGet window in the Visual Studio by right clicking the Project and selecting NuGet Package Manager, and on the "Online" tab type "Lowercase Dashed Route", and it should pop up.

Alternatively, you can run this code in the Package Manager Console:

Install-Package LowercaseDashedRoute

After that you should open App_Start/RouteConfig.cs and comment out existing route.MapRoute(...) call and add this instead:

routes.Add(new LowercaseDashedRoute("{controller}/{action}/{id}",
  new RouteValueDictionary(
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }),
    new DashedRouteHandler()
  )
);

That's it. All the urls are lowercase, dashed, and converted implicitly without you doing anything more.

Open Source Project Url: https://github.com/AtaS/lowercase-dashed-route

七秒鱼° 2024-12-27 15:25:04

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

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

Hanselman 有一个很好的例子E:

< a href="http://www.hanselman.com/blog/ASPNETMVCAndTheNewIIS7RewriteModule.aspx" rel="nofollow">http://www.hanselman.com/blog/ASPNETMVCAndTheNewIIS7RewriteModule.aspx

此外为什么不下载像 ReSharper 或 CodeRush 这样的东西,并用它来重构操作和路由名称?这真的很简单,而且非常安全。

通过一个小时的重构来修复路由/操作命名约定的时间会比您已经花费在尝试根据需要更改路由约定的所有时间要少得多。

只是一个想法。

Have you tried working with the URL Rewrite package? I think it pretty much what you are looking for.

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

Hanselman has a great example herE:

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

Also, why don't you download something like ReSharper or CodeRush, and use it to refactor the Action and Route names? It's REALLY easy, and very safe.

It would time well spent, and much less time overall to fix your routing/action naming conventions with an hour of refactoring than all the hours you've already spent trying to alter the routing conventions to your needs.

Just a thought.

想挽留 2024-12-27 15:25:04

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

使用典型的 {controller}/{action}/{id} 默认路由、名为 CatalogController 的控制器以及其中的操作方法,如下所示:

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

我注意到对“/catalog/quick-select/1234”的请求工作得很好,但对 /catalog/quick-select?id=1234 的请求是 500'ing,因为一旦由于以下原因调用了操作方法controller.Execute(),action 方法内的 id 参数为 null。

我不知道具体原因,但行为就好像 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:博士; - 这就是我所做的:

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

I tried the solution in the accepted answer above: Using the Canonicalize Pattern url strategy, and then also adding a custom IRouteHandler which then returns a custom IHttpHandler. It mostly worked. Here's one caveat I found:

With the typical {controller}/{action}/{id} default route, a controller named CatalogController, and an action method inside it as follows:

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

I noticed that requests to "/catalog/quick-select/1234" worked perfectly, but requests to /catalog/quick-select?id=1234 were 500'ing because once the action method was called as a result of controller.Execute(), the id parameter was null inside of the action method.

I do not know exactly why this is, but the behavior was as if MVC was not looking at the query string for values during model binding. So something about the ProcessRequest implementation in the accepted answer was screwing up the normal model binding process, or at least the query string value provider.

This is a deal breaker, so I took a look at default MVC IHttpHandler (yay open source!): http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/MvcHandler.cs

I will not pretend that I grok'ed it in its entirety, but clearly, it's doing ALOT more in its implementation of ProcessRequest than what is going on in the accepted answer.

So, if all we really need to do is strip dashes from our incoming route data so that MVC can find our controllers/actions, why do we need to implement a whole stinking IHttpHandler? We don't! Simply rip out the dashes in the GetHttpHandler method of DashedRouteHandler and pass the requestContext along to the out of the box MvcHandler so it can do its 252 lines of magic, and your route handler doesn't have to return a second rate IHttpHandler.

tl:dr; - Here's what I did:

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);
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文