HTTP PUT or DELETE not allowed? Use X-HTTP-Method-Override for your REST Service with ASP.NET Web API
I got an email today where someone had built a REST(ful/ish) API with ASP.NET Web API that had a customer who was against the idea of using GET, POST, PUT, and DELETE, and insisted that they only use GET and POST.
Sometimes this is because of a browser or client limitaton, sometimes it's a really tense corporate firewall. They wanted to know what they could do.
One thing you can do is to "tunnel" HTTP Methods inside another HTTP Header. Basically you have a header that says "No, seriously, I know I got here via a POST, but use this one instead." You would still POST, but then you'd have "X-HTTP-Method-Override:PUT" as a header.
Here is a PUT in the Postman REST client:
So that's:
PUT /api/Person/4 HTTP/1.1
Host: localhost:10320
Content-Type: application/json
Cache-Control: no-cache
And here's the same PUT, except as a POST plus an X-HTTP-Method-Override header.
Raw, that's like this:
POST /api/Person/4 HTTP/1.1
Host: localhost:10320
Content-Type: application/json
X-HTTP-Method-Override: PUT
Cache-Control: no-cache
Now, how do you get ASP.NET Web API to respect this new way to route things? You may have a Web API Controller like this:
public IEnumerable<Person> Get() { }
// GET api/person/5
public Person Get(int id) { }
// POST api/person
public void Post([FromBody]Person value) { }
// PUT api/person/5
public void Put(int id, [FromBody]Person value) { }
// DELETE api/person/5
public void Delete(int id) { }
And you likely don't want to change it. Make a MethodOverrideHandler like this one. You can add the code yourself, get it from a NuGet package, or use one from the WebAPIContrib project. It's up to you.
public class MethodOverrideHandler : DelegatingHandler
{
readonly string[] _methods = { "DELETE", "HEAD", "PUT" };
const string _header = "X-HTTP-Method-Override";
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
// Check for HTTP POST with the X-HTTP-Method-Override header.
if (request.Method == HttpMethod.Post && request.Headers.Contains(_header))
{
// Check if the header value is in our methods list.
var method = request.Headers.GetValues(_header).FirstOrDefault();
if (_methods.Contains(method, StringComparer.InvariantCultureIgnoreCase))
{
// Change the request method.
request.Method = new HttpMethod(method);
}
}
return base.SendAsync(request, cancellationToken);
}
}
You see it checks if it's a post, looks for the extra header, then changes the request's Method property after the message has been received, but before it's been sent through the pipeline. It'll show up on the right method just as if a PUT had been sent, because from its perspective, a PUT was sent.
You need to register this new MethodOverrideHandler in your WebApiConfig like this, just by adding to the MessageHandlers collection, next to the rest of the configuration and routing code.
public static void Register(HttpConfiguration config)
{
config.MessageHandlers.Add(new MethodOverrideHandler());
//OTHER REGULAR STUFF HERE
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
On the client side, you can keep sending a post with your .ajax call in jQuery, for example, just make sure the override header in there.
$.ajax({
url: "http://localhost:10320/api/Person/4",
type: "POST",
data: JSON.stringify(whatever),
headers: {
"Content-Type": "application/json",
"X-HTTP-Method-Override": "PUT" },
})
That's the general idea, enjoy!
Sponsor: Big Thanks to Aspose for sponsoring the blog this week! Aspose.Total for .NET has all the APIs you need to create, manipulate and convert Microsoft Office documents and a host of other file formats in your applications. Curious? Start a free trial today.
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
I did something similar to fix URL generation when the WebAPI service is behind an SSL terminating load balancer.
Thanks for sharing this. I remember similar implementations for WCF REST using custom endpoint behaviors. Although, I'm wondering why doesn't Web API (and also WCF REST) support this "out of the box"? The "X-HTTP-Method-Override" is a well-known (and widely used, not only in the context of Web API) method, so making this a built-in functionality would certainly make our lives a bit easier.
Cheers!
In which case, why not just have a polymorhpic POST handler on the WEB API side that can do UPSERT-y type behavior?
https://github.com/WebApiContrib/WebAPIContrib/blob/master/src/WebApiContrib/MessageHandlers/MethodOverrideHandler.cs
Can any one shed any light; is there any legitimate reason for these verbs to be blocked? Or are said admin's just being asshats?
I'd be saying to the customer (words to the effect): "well we can re-work the design of the application to support the fact that your IT guys want to be asshats but it's going to cost you £X for us to do and it will take Y amount of time. Alternatively you can ask them to remove a pointless restriction which will take 5 minutes and cost nothing, it's up to you."
Comments are closed.