与另一个路由匹配的路由,忽略 HttpMethodConstraint?

发布于 2024-10-20 02:59:37 字数 1003 浏览 3 评论 0原文

我有一个 ASP.net MVC 3 站点,其路由如下:

routes.MapRoute("Get", "endpoint/{id}",
    new { Controller = "Foo", action = "GetFoo" },
    new { httpMethod = new HttpMethodConstraint("GET") });

routes.MapRoute("Post", "endpoint/{id}",
    new { Controller = "Foo", action = "NewFoo" },
    new { httpMethod = new HttpMethodConstraint("POST") });

routes.MapRoute("BadFoo", "endpoint/{id}",
    new { Controller = "Error", action = "MethodNotAllowed" });

routes.MapRoute("NotFound", "", 
    new { controller = "Error", action = "NotFound" });

因此,简而言之,我有一个与某些 HTTP 动词(如 GET 和 POST)匹配的路由,但在其他 HTTP 动词(如 PUT 和 DELETE)上匹配,它应该返回特定错误。

我的默认路由是 404。

如果我删除“BadFoo”路由,则针对端点/{id} 的 PUT 将返回 404,因为其他路由都不匹配,因此它会转到我的 NotFound 路由。

问题是,我有大量像 Get 和 Post 这样的路由,其中​​我有一个 HttpMethodConstraint,并且我必须创建一个像 BadFoo 路由这样的路由,只是为了捕获路由字符串上的正确匹配,而不是方法上的正确匹配,这会爆炸不必要地增加我的路由。

如何仅使用 Get、Post 和 NotFound 路由设置路由,同时仍区分 HTTP 404 未找到(=无效 URL)和 HTTP 405 方法不允许(=有效 URL、错误的 HTTP 方法)?

I have an ASP.net MVC 3 Site with routes like this:

routes.MapRoute("Get", "endpoint/{id}",
    new { Controller = "Foo", action = "GetFoo" },
    new { httpMethod = new HttpMethodConstraint("GET") });

routes.MapRoute("Post", "endpoint/{id}",
    new { Controller = "Foo", action = "NewFoo" },
    new { httpMethod = new HttpMethodConstraint("POST") });

routes.MapRoute("BadFoo", "endpoint/{id}",
    new { Controller = "Error", action = "MethodNotAllowed" });

routes.MapRoute("NotFound", "", 
    new { controller = "Error", action = "NotFound" });

So in a Nutshell, I have a Route that matches on certain HTTP Verbs like GET and POST but on other HTTP Verbs like PUT and DELETE it should return a specific error.

My default Route is a 404.

If I remove the "BadFoo" route, then a PUT against endpoint/{id} returns a 404 because none of the other routes match, so it goes to my NotFound route.

The thing is, I have a ton of routes like Get and Post where I have an HttpMethodConstraint and where I would have to create a route like the BadFoo route just to catch a correct match on the route string but not on the Method, which blows up my routing unnecessarily.

How could I setup routing with only the Get, Post and NotFound routes while still differentiating between a HTTP 404 not found (=invalid URL) and HTTP 405 Method not allowed (=valid URL, wrong HTTP Method)?

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

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

发布评论

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

评论(1

谷夏 2024-10-27 02:59:37

您可以使用自定义 ControllerActionInvokerActionMethodSelector 属性(如 [HttpGet])将 HTTP 方法验证委托给 MVC 运行时,而不是使用路由约束, [HttpPost] 等:

using System;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MvcApplication6.Controllers {

   public class HomeController : Controller {

      protected override IActionInvoker CreateActionInvoker() {
         return new CustomActionInvoker();
      }

      [HttpGet]
      public ActionResult Index() {
         return Content("GET");
      }

      [HttpPost]
      public ActionResult Index(string foo) {
         return Content("POST");
      }
   }

   class CustomActionInvoker : ControllerActionInvoker {

      protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName) {

         // Find action, use selector attributes
         var action = base.FindAction(controllerContext, controllerDescriptor, actionName);

         if (action == null) {

            // Find action, ignore selector attributes
            var action2 = controllerDescriptor
               .GetCanonicalActions()
               .FirstOrDefault(a => a.ActionName.Equals(actionName, StringComparison.OrdinalIgnoreCase));

            if (action2 != null) {
               // Action found, Method Not Allowed ?
               throw new HttpException(405, "Method Not Allowed");
            }
         }

         return action;
      }
   }
}

请注意我的最后一条评论“找到操作,不允许方法?”,我将其写为一个问题,因为可能存在不支持的 ActionMethodSelector 属性与 HTTP 方法验证相关...

Instead of using route constraint you can delegate the HTTP method validation to the MVC runtime, using a custom ControllerActionInvoker and ActionMethodSelector attributes like [HttpGet], [HttpPost], etc.:

using System;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MvcApplication6.Controllers {

   public class HomeController : Controller {

      protected override IActionInvoker CreateActionInvoker() {
         return new CustomActionInvoker();
      }

      [HttpGet]
      public ActionResult Index() {
         return Content("GET");
      }

      [HttpPost]
      public ActionResult Index(string foo) {
         return Content("POST");
      }
   }

   class CustomActionInvoker : ControllerActionInvoker {

      protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName) {

         // Find action, use selector attributes
         var action = base.FindAction(controllerContext, controllerDescriptor, actionName);

         if (action == null) {

            // Find action, ignore selector attributes
            var action2 = controllerDescriptor
               .GetCanonicalActions()
               .FirstOrDefault(a => a.ActionName.Equals(actionName, StringComparison.OrdinalIgnoreCase));

            if (action2 != null) {
               // Action found, Method Not Allowed ?
               throw new HttpException(405, "Method Not Allowed");
            }
         }

         return action;
      }
   }
}

Note my last comment 'Action found, Method Not Allowed ?', I wrote this as a question because there can be ActionMethodSelector attributes that are not related with HTTP method validation...

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