I was searching for an answer to this question, and found this question, which is indeed very similar. However the solutions(s) posted there don't seem to be working for me... I wonder if it has to do with the question's age.
Given the following URL:
/my/items/6
I want HTTP PUT requests for this URL to be handled by one action method, and HTTP DELETE requests to be handled by another action method. Below are the routes I defined (note these are based in an area, so context
is an AreaRegistrationContext
instance, if that matters):
context.MapRoute(null,
"my/items/{id}",
new { area = "AreaName", controller = "ControllerName", action = "Replace" },
new
{
httpMethod = new HttpMethodConstraint("POST", "PUT"),
}
);
context.MapRoute(null,
"my/items/{id}",
new { area = "AreaName", controller = "ControllerName", action = "Destroy" },
new
{
httpMethod = new HttpMethodConstraint("POST", "DELETE"),
}
);
URL generation works fine with both of these routes, however there are problems when routing incoming requests. Only the first-declared route correctly maps to its respective action.
I dug into the HttpMethodConstraint
source code and discovered that it does not care about the "X-HTTP-Method-Override"
parameter, only HttpContext.Request.HttpMethod
.
I was able to solve this problem with the following custom route constraint class:
public class HttpMethodOverrideConstraint : HttpMethodConstraint
{
public HttpMethodOverrideConstraint(params string[] allowedMethods)
: base(allowedMethods) { }
protected override bool Match(HttpContextBase httpContext, Route route,
string parameterName, RouteValueDictionary values,
RouteDirection routeDirection)
{
var methodOverride = httpContext.Request
.Unvalidated().Form["X-HTTP-Method-Override"];
if (methodOverride == null)
return base.Match(httpContext, route, parameterName,
values, routeDirection);
return
AllowedMethods.Any(m =>
string.Equals(m, httpContext.Request.HttpMethod,
StringComparison.OrdinalIgnoreCase))
&&
AllowedMethods.Any(m =>
string.Equals(m, methodOverride,
StringComparison.OrdinalIgnoreCase))
;
}
}
...and these route definitions:
context.MapRoute(null,
"my/items/{id}",
new { area = "AreaName", controller = "ControllerName", action = "Replace" },
new
{
httpMethod = new HttpMethodOverrideConstraint("POST", "PUT"),
}
);
context.MapRoute(null,
"my/items/{id}",
new { area = "AreaName", controller = "ControllerName", action = "Destroy" },
new
{
httpMethod = new HttpMethodOverrideConstraint("POST", "DELETE"),
}
);
My question: is it really necessary to have a custom route constraint to accomplish this? Or is there any way to make it work out-of-the-box with standard MVC & routing classes?