9

I have Web Api 2 backend hosted on Azure and AngularJs forntend. I understand that some of HTTP request use pre-check with OPTIONS request. My question is how to implement backend that way, that all OPTIONS requests will return 200 if there is some action in controller that will handle following GET/POST/PUT/DELETE/....

Matjaž
  • 2,096
  • 3
  • 35
  • 55

2 Answers2

19

Non elegant way to solve this task is adding in each controller manually

[AcceptVerbs("OPTIONS")]
public HttpResponseMessage Options()
{
    var resp = new HttpResponseMessage(HttpStatusCode.OK);
    resp.Headers.Add("Access-Control-Allow-Origin", "*");
    resp.Headers.Add("Access-Control-Allow-Methods", "GET,DELETE");

    return resp;
}

Or override MessageHandlers

 public class OptionsHttpMessageHandler : DelegatingHandler
{
  protected override Task<HttpResponseMessage> SendAsync(
  HttpRequestMessage request, CancellationToken cancellationToken)
  {
    if (request.Method == HttpMethod.Options)
      {
         var apiExplorer = GlobalConfiguration.Configuration.Services.GetApiExplorer();

          var controllerRequested = request.GetRouteData().Values["controller"] as string;              
          var supportedMethods = apiExplorer.ApiDescriptions.Where(d => 
             {  
                var controller = d.ActionDescriptor.ControllerDescriptor.ControllerName;
                return string.Equals(
                    controller, controllerRequested, StringComparison.OrdinalIgnoreCase);
            })
          .Select(d => d.HttpMethod.Method)
          .Distinct();

      if (!supportedMethods.Any())
         return Task.Factory.StartNew(
             () => request.CreateResponse(HttpStatusCode.NotFound));

      return Task.Factory.StartNew(() =>
        {
            var resp = new HttpResponseMessage(HttpStatusCode.OK);
            resp.Headers.Add("Access-Control-Allow-Origin", "*");
            resp.Headers.Add(
                "Access-Control-Allow-Methods", string.Join(",", supportedMethods));

            return resp;
        });
}

return base.SendAsync(request, cancellationToken);

  }
}

and then in config

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

even second option is not perfect though... no native build in support

Vladimir
  • 1,380
  • 2
  • 19
  • 23
  • 2
    or inherit from your own base class which contains your public HttpResponseMessage Options() method: public abstract class BaseApiController : ApiController – Rob Sedgwick Jan 05 '18 at 16:23
14

I had the same issue as you, the so called Preflight request, and I figured out that this might be related to a misconfiguration on the Web.Conf file. Comment out or remove, if present, the line containing the "remove" of the OPTIONSVerbHandler.

<system.webServer>
<handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <!--<remove name="OPTIONSVerbHandler" /> -->
      <remove name="TRACEVerbHandler" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
</system.webServer>
Alessandro R
  • 525
  • 7
  • 16