匹配另一条路线的路线,忽略HttpMethodConstraint?

时间:2011-03-01 21:55:19

标签: .net asp.net-mvc asp.net-mvc-3 routing asp.net-mvc-routing

我有一个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" });

所以在Nutshell中,我有一个匹配某些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方法)?

1 个答案:

答案 0 :(得分:4)

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

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

请注意我的上一条评论“发现的操作,方法不允许?”,我将此写为一个问题,因为可能存在与HTTP方法验证无关的ActionMethodSelector个属性...