AngularJS $http.post and OPTIONS verbs with C# MVC apps
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!
Where does the code to register go?
I’m not sure I understand your question?
Are you talking about making a custom handler class?