A route that matches another route, ignoring the HttpMethodConstraint?

I have an ASP.net MVC 3 site with these types of routes:

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 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 404.

If I delete the β€œBadFoo” route, then PUT against the endpoint / {id} returns 404, because none of the other routes matches, so it goes to my NotFound route.

The fact is that I have a ton of routes, such as Get and Post, where I have HttpMethodConstraint, and where I will need to create a route, for example a BadFoo route, to catch the correct match in the route string, but not on the method that is redundant way disables my routing.

How to configure routing only with Get, Post, and NotFound routes, but distinguish between HTTP 404 not found (= invalid URL) and HTTP method 405 not allowed (= valid URL, invalid HTTP method)?

+4
source share
1 answer

Instead of using route restrictions, you can delegate the HTTP method check to the MVC runtime using the custom attributes ControllerActionInvoker and ActionMethodSelector , such as [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; } } } 

Pay attention to my last comment β€œAction found, method not resolved?”, I wrote it as a question, because there may be ActionMethodSelector attributes that are not related to HTTP method validation ...

+4
source

Source: https://habr.com/ru/post/1341885/


All Articles