2011-03-01 65 views
4

我有一个ASP.net MVC 3网站与路线是这样的:匹配另一个路由的路由,忽略HttpMethodConstraint?

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" }); 
果壳

所以,我有一个像GET和POST某些HTTP动词,但是,像PUT等HTTP动词相匹配的路由删除它应该返回一个特定的错误。

我的默认路由是404

如果我删除“BadFoo”的路线,那么对端点/ {ID} PUT返回一个404,因为没有任何其他途径比赛,所以去我NOTFOUND路线。

事情是,我有很多像Get和Post这样的路线,我有一个HttpMethodConstraint,并且我将不得不创建像BadFoo路线一样的路线,以便在路线字符串上捕获正确的匹配,但不在方法,它不必要地炸毁了我的路由。

如何在只有Get,Post和NotFound路由的情况下设置路由,同时仍然区分HTTP 404未找到(=无效的URL)和HTTP 405方法不允许(=有效的URL,错误的HTTP方法)?

+0

如果使用[HttpGet]和[HttpPost]明确标记控制器方法,会发生什么情况?而不是使用路线?这会使PUT和DELETE请求引发正确的异常吗? – 2011-03-03 13:52:53

+0

有人提出这是MS Connect上的一个错误(我同意,在这种情况下,他们没有正确实现HTTP响应代码)。然而,它被设计封闭了 - 显然他们宁愿你为所有动词编写单行“抛405方法不允许”的控制器方法。但我更喜欢Max的解决方法。链接:http://connect.microsoft.com/VisualStudio/feedback/details/419729/asp-net-mvc-return-http-status-code-405-method-not-allowed-if-a-valid-route-存在,但是,没有 - 的最动作 - 重载 - 接受 - 在指定法 – 2012-02-23 12:02:15

回答

4

而不是使用路由约束可以委派的HTTP方法验证的MVC运行时,使用自定义ControllerActionInvokerActionMethodSelector属性像[HttpGet][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方法验证无关...