08 Dec 2014

AngularJS $http.post and OPTIONS verbs with C# MVC apps

development 2 Comments

If you have an angular service that posts data, the $http object will do a pre-flight OPTIONS request to the URL to make sure it can post.

1 $http.post('/someUrl', {msg:'hello word!'}). 2 success(function(data, status, headers, config) { 3 console.log(data); 4 }). 5 error(function(data, status, headers, config) { 6 console.log('error'); 7 });

On the flip side, don’t expect IIS to respect this.

In attempts to do this with AngularJs and the ionic framework, I was getting 404’s when calling post and nothing made any sense. Chrome debugging showed the OPTIONS call happening in Network.

After gnashing of teeth (aka googling) – I found the solution on Jef Claes’ blog.

Effectively, you have to obviously allow the OPTIONS verb, but there are two approaches he offers.

A granular, less elegant solution; handing it in controller. To do this, you’ll need to namespaces:

System.Net & System.Net.Http.

In my use case, I have a controller for various API requests, instead of a single controller for all API.

1 [AcceptVerbs("OPTIONS")] 2 public HttpResponseMessage ApiVerbName() 3 { 4 var resp = new HttpResponseMessage(HttpStatusCode.OK); 5 resp.Headers.Add("Access-Control-Allow-Origin", "*"); 6 resp.Headers.Add("Access-Control-Allow-Methods", "GET,DELETE"); 7 8 return resp; 9 }

Great, but then not so great, so the other option Jef details is a HTTP message handler.

In this approach, you create a new class, inherit from DelegatingHandler .  This is Jef’s example, exactly.

1 public class OptionsHttpMessageHandler : DelegatingHandler 2 { 3 protected override Task<HttpResponseMessage> SendAsync( 4 HttpRequestMessage request, CancellationToken cancellationToken) 5 { 6 if (request.Method == HttpMethod.Options) 7 { 8 var apiExplorer = GlobalConfiguration.Configuration.Services.GetApiExplorer(); 9 10 var controllerRequested = request.GetRouteData().Values["controller"] as string; 11 var supportedMethods = apiExplorer.ApiDescriptions 12 .Where(d => 13 { 14 var controller = d.ActionDescriptor.ControllerDescriptor.ControllerName; 15 return string.Equals( 16 controller, controllerRequested, StringComparison.OrdinalIgnoreCase); 17 }) 18 .Select(d => d.HttpMethod.Method) 19 .Distinct(); 20 21 if (!supportedMethods.Any()) 22 return Task.Factory.StartNew( 23 () => request.CreateResponse(HttpStatusCode.NotFound)); 24 25 return Task.Factory.StartNew(() => 26 { 27 var resp = new HttpResponseMessage(HttpStatusCode.OK); 28 resp.Headers.Add("Access-Control-Allow-Origin", "*"); 29 resp.Headers.Add( 30 "Access-Control-Allow-Methods", string.Join(",", supportedMethods)); 31 32 return resp; 33 }); 34 } 35 36 return base.SendAsync(request, cancellationToken); 37 } 38 }

Lastly – register it in the config:

GlobalConfiguration.Configuration.MessageHandlers.Add(new OptionsHttpMessageHandler());

 

I’m posting this so I won’t lose it and in hopes it is easier to find for someone else.

Good luck!

2 Responses to “AngularJS $http.post and OPTIONS verbs with C# MVC apps”

  1. ben says:

    Where does the code to register go?

Leave a Reply

Currently you have JavaScript disabled. In order to post comments, please make sure JavaScript and Cookies are enabled, and reload the page. Click here for instructions on how to enable JavaScript in your browser.