Is it possible to implement X-HTTP-Method-Override in ASP.NET MVC?
Asked Answered
G

8

5

I'm implementing a prototype of a RESTful API using ASP.NET MVC and apart from the odd bug here and there I've achieve all the requirements I set out at the start, apart from callers being able to use the X-HTTP-Method-Override custom header to override the HTTP method.

What I'd like is that the following request...

GET /someresource/123 HTTP/1.1
X-HTTP-Method-Override: DELETE

...would be dispatched to my controller method that implements the DELETE functionality rather than the GET functionality for that action (assuming that there are multiple methods implementing the action, and that they are marked with different [AcceptVerbs] attributes). So, given the following two methods, I would like the above request to be dispatched to the second one:

[ActionName("someresource")]
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult GetSomeResource(int id) { /* ... */ }

[ActionName("someresource")]
[AcceptVerbs(HttpVerbs.Delete)]
public ActionResult DeleteSomeResource(int id) { /* ... */ }

Does anybody know if this is possible? And how much work would it be to do so...?

Gangling answered 21/1, 2009 at 23:41 Comment(0)
M
5

You won't be able to use the [AcceptVerbs] attribute as-is since it's tied to the request's actual HTTP verb. Fortunately the [AcceptVerbs] attribute is very simple; you can see the source for yourself at http://www.codeplex.com/aspnet/SourceControl/changeset/view/21528#266431.

In short, subclass AcceptsVerbsAttribute and override the IsValidForRequest() method. The implementation would be something like the following:

string incomingVerb = controllerContext.HttpContext.Request.Headers["X-HTTP-Method-Override"] ?? controllerContext.HttpContext.Request.Method;
return Verbs.Contains(incomingVerb, StringComparer.OrdinalIgnoreCase);
Meara answered 29/1, 2009 at 7:6 Comment(3)
I had to nick the code from AcceptVerbsAttribute and implement my own one as unfortunately it's sealed, but the approach works perfectly and is nice and simple, so looks like you get the 300 points!Gangling
hi levi, however my ASP.net IIS or MVC is denying DELETE and PUT request, is there anyway to get this work? I tried to put Allow: PUT, DELETE into IIS Allow header but it won't work...Tracheotomy
Duc, I know it's been a LONG LONG LONG LONG time, but see if WebDav is installed. If it is, uninstall it. Otherwise, it'll intercept your PUT and DELETE requests.Marsden
E
3

Levi's answer is great. Additionally, I added a check in the custom AcceptsVerbsAttribute that also examines the FORM collection, so you can simply put a hidden input to trigger the DELETE (similar to MVC 2's Html.HttpMethodOverride(HttpVerbs.Delete)).

<input name="X-HTTP-Method-Override" type="hidden" value="DELETE" />

Change the incomingVerb assignment to:

string incomingVerb = controllerContext.HttpContext.Request.Headers["X-HTTP-Method-Override"] ?? controllerContext.HttpContext.Request.Form["X-HTTP-Method-Override"] ??controllerContext.HttpContext.Request.HttpMethod;

Be careful with this approach! See a related post by Stephen Walther.

Hopefully this helps someone.

East answered 18/2, 2010 at 0:40 Comment(1)
Another possible solution to send it in the content-type header as a MIME type parameter.Cartilaginous
A
3

Insert to Form:

<%= Html.HttpMethodOverride(HttpVerbs.Delete) %>
Ashliashlie answered 7/6, 2010 at 4:3 Comment(0)
P
2

This conversation is a bit old, but I wanted to share what I have found using mvc 2:

Browsers support two HTTP verbs: GET and POST, but ASP.NET MVC 2 allows you to simulate Put, Get, and Delete using Html.HttpMethodOverride helper method. Internally, this works by sending the verb in an X-HTTP-Method-Override form field. The behavior of HttpMethodOverride is used by the [AcceptVerbs] attribute as well as the new shorter verb attributes:

For example, the action declaration:

[ActionName("someresource")]
[HttpDelete]
public ActionResult DeleteSomeResource()

should take responsibility for your get request that has the X-HTTP-Method-Override set to Delete.

Particulate answered 21/10, 2010 at 20:12 Comment(1)
Not just in form field. Can be in Header or query string as well. The idea is that HTTP method overriding is supported. +1Tager
W
2

I'm surprised that this hasn't been mentioned yet, but ASP.NET MVC natively supports X-HTTP-Method-Override and has been doing so from at least version 2. There's no need to write custom code to handle this.

It work in the following way:

Inside AcceptVerbsAttribute (also proxied by [HttpPut], [HttpPost], etc), there's an IsValidForRequest method. Inside that method, it checks with Request.GetHttpMethodOverride(), which returns the proper overriden HTTP method with the following conditions:

  • Overriding is only supported in POST requests. All others are ignored.
  • If the X-HTTP-Method-Override value is GET or POST, it's ignored. This makes sense, as you'd never need to override with these values.
  • It looks for X-HTTP-Method-Override in the following places in this priority: 1) HTTP Header 2) Form Body 3) Query String

If you're really curious, here's how GetHttpMethodOverride() looks (from MVC 3's source code):

public static class HttpRequestExtensions {
    internal const string XHttpMethodOverrideKey = "X-HTTP-Method-Override";

    public static string GetHttpMethodOverride(this HttpRequestBase request) {
        if (request == null) {
            throw new ArgumentNullException("request");
        }

        string incomingVerb = request.HttpMethod;

        if (!String.Equals(incomingVerb, "POST", StringComparison.OrdinalIgnoreCase)) {
            return incomingVerb;
        }

        string verbOverride = null;
        string headerOverrideValue = request.Headers[XHttpMethodOverrideKey];
        if (!String.IsNullOrEmpty(headerOverrideValue)) {
            verbOverride = headerOverrideValue;
        }
        else {
            string formOverrideValue = request.Form[XHttpMethodOverrideKey];
            if (!String.IsNullOrEmpty(formOverrideValue)) {
                verbOverride = formOverrideValue;
            }
            else {
                string queryStringOverrideValue = request.QueryString[XHttpMethodOverrideKey];
                if (!String.IsNullOrEmpty(queryStringOverrideValue)) {
                    verbOverride = queryStringOverrideValue;
                }
            }
        }
        if (verbOverride != null) {
            if (!String.Equals(verbOverride, "GET", StringComparison.OrdinalIgnoreCase) &&
                !String.Equals(verbOverride, "POST", StringComparison.OrdinalIgnoreCase)) {
                incomingVerb = verbOverride;
            }
        }
        return incomingVerb;
    }
}
Waw answered 31/5, 2013 at 14:9 Comment(0)
M
1

Have you looked at Simply Restful Routing? It already does this.

Edited Feb 2010 to add: Method overrides are built into MVC 2.

Miguelinamiguelita answered 22/1, 2009 at 14:13 Comment(3)
I don't see anything about it implementing X-HTTP-Method-Override and a quick scan of the source doesn't reveal anything. Are you sure about this? If so could you point me to the file in which it's implemented in? Cheers!Gangling
X-HTTP-Method-Override is one person's design for supporting non-GET/POST requests. Simply Restful Routing is another. Different design, same goal.Miguelinamiguelita
I don't really want to combine REST with RPC style URLs (I'm happy with one or the other, but would prefer to avoid a combination of both) so I think I'd rather go with the header option than with action links as in the Simply Restful design.Gangling
R
0

The X-HTTP-Method-Override is a custom header and most likely isn't supported by your web container.

Are you calling this from a web page? If so, you should probably use XmlHttpRequest with DELETE (or whatever verb you want). Better yet, use a JS framework to do the heavy lifting for you.

Radioelement answered 21/1, 2009 at 23:57 Comment(4)
I'm not calling it, I'm implementing it... And I want to make the implementation support the custom header.Gangling
I don't understand. If you control the implementation, why on earth would you not use HTTP the way it was designed by using the standard verbs?Radioelement
Because unfortunately some clients, proxies and firewalls do not allow verbs other than GET or POST, so sometimes people need to be able to fake DELETE with GET and PUT with POST. It's a bit lame, but most RESTful services seem to support this header.Gangling
It's dangerous to map GET to anything else. GET should be side effect free. We should only override POSTsProtoxylem
C
0

You could create an ActionFilter that implements OnActionExecuting, which fires before the controller action is invoked. You could then interrogate the request headers, and redirect based on the value of the X-HTTP-Method-Override header, when present.

Conviction answered 22/1, 2009 at 0:5 Comment(1)
At that point won't it have already done the parameter binding for the action it thought it was going to call though? The methods may have different parameters. I think that maybe I need to hook in before the action is selected by the dispatched?Gangling

© 2022 - 2024 — McMap. All rights reserved.