Dor Cohen
Dor Cohen

Reputation: 17080

Wcf webHttpBinding Response for preflight has invalid HTTP status code 400

I followed Ido Flatow's post to create a cross-origin request and created the following:

On my service interface:

[OperationContract]
[WebInvoke(Method = "*", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
bool GetUserAuthentication(string userLoginName, string password);

On app.config:

<behaviors>
  <endpointBehaviors>
    <behavior name="webSupport">
      <webHttp />
      <CorsSupport />
    </behavior>
  </endpointBehaviors>
</behaviors>

<extensions>
  <behaviorExtensions>
    <add name="CorsSupport" type="WebHttpCors.CorsSupportBehaviorElement, WebHttpCors, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  </behaviorExtensions>
</extensions>

Now I'm sending a simple post request using angular $http service and it's working on IE & Edge (also on Postman) but fails to work on Chrome & Firefox with the following error:

XMLHttpRequest cannot load http://localhost:5280/MetaDataService/GetUserAuthentication. Response for preflight has invalid HTTP status code 400

Chrome error printscreen:

Error

Upvotes: 3

Views: 4862

Answers (2)

Amir Touitou
Amir Touitou

Reputation: 3441

1.Add this API to the IRestService (your service interface)

[OperationContract]
[WebInvoke(Method = "OPTIONS", UriTemplate = "*")]
void Options();

2.Implement this function in the RestService (your service implemention)

public void Options()
{
    WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
    WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
    WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type");
}

CORS operation

There are two types of requests in the CORS world, “normal” requests and preflight requests. Normal requests are the requests which the page would normally make to the service, with an additional header, “Origin”, which indicates the origin and the service can determine whether to allow cross-domain calls from that origin or not (via the “Access-Control-Allow-Origin” response header). “Safe” requests (GET and HEAD) only use that extra headers to work. The browser will add the Origin header to requests going to domains other than the one where the page originated, and if the service doesn’t allow that domain, then the call will fail.

“Unsafe” requests, such as POST, PUT or DELETE, can’t be done the same way. If the service isn’t CORS-aware, it would ignore the “Origin” header and accept the request, with possible side effects (e.g., deleting a record), and at the time the client gets the response, the browser could still “fail” the request, but the damage has already been done. What the browser does in those cases is to first send a preflight request, which is a HTTP OPTIONS request asking for permission to send the actual request. If the service answers that request allowing the call, only then the browser will send the user request to the service.

Upvotes: 0

Dor Cohen
Dor Cohen

Reputation: 17080

Chrome is preflighting the request to look for CORS headers. If the request is acceptable, it will then send the real request.

My problem was that the OPTIONS request which sent to my WCF server was rejected I defined Method="*" for my method, causing the options request to be directed to my method and was expecting to get also parameters.

The solution for this based on How to handle Ajax JQUERY POST request with WCF self-host question was to add new OperationContract for dealing with OPTIONS requests:

[OperationContract]
[WebInvoke(Method = "OPTIONS", UriTemplate = "*")]
void GetOptions();

public void GetOptions()
{
}

this method gets all options request and allowing the real POST method being directed to my service method.

Upvotes: 8

Related Questions