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

后端 未结 8 1703
遥遥无期
遥遥无期 2020-12-18 08:02

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 f

相关标签:
8条回答
  • 2020-12-18 08:35

    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.

    0 讨论(0)
  • 2020-12-18 08:39

    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);
    
    0 讨论(0)
  • 2020-12-18 08:45

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

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

    0 讨论(0)
  • 2020-12-18 08:47

    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;
        }
    }
    
    0 讨论(0)
  • 2020-12-18 08:53

    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.

    0 讨论(0)
  • 2020-12-18 08:56

    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.

    0 讨论(0)
提交回复
热议问题