11
votes

I have read many similar problems in StackOverflow, but the solutions doesn't work for me.

I have WCF REST service:

[<OperationContract>]    
    [<WebInvoke(UriTemplate = "PostItem", 
            RequestFormat= WebMessageFormat.Json,   
            ResponseFormat = WebMessageFormat.Json, Method = "POST")>]         

I can use it using Postman (Chrome extension). I am passing data as 'raw', not 'urlencoded'. And I get 200 return code.

enter image description here

I need to call this method using angularjs:

    $http.post('http://192.168.1.65/Service1.svc/restapi/PostItem',                   
                {
    "Address": "г. Москва, ул. Соколово-Мещерская, д.25",
     ...
    "User": ""
      })  

I have just copied URL and JSON from Postman. But I get the error:

angular.js:10722 OPTIONS http://192.168.1.65/Service1.svc/restapi/PostItem http://192.168.1.65/Service1.svc/restapi/PostItem. Response for preflight has invalid HTTP status code 405

I have searched similar problems and have found two solutions:

  1. Use jQuery to set header Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', but it doesn't work with my WCF service
  2. Set custom headers in my Web.Config:

    <httpProtocol>
       <customHeaders>
          <add name="Access-Control-Allow-Origin" value="*" />
          <add name="Access-Control-Allow-Headers" value="Content-Type" />
          <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
       </customHeaders>
    </httpProtocol>
    

It doesn't help me. And I am not sure that the reason of the error on the server side. The Postman extension can call this method succesfully.

How can I make the same POST call using AngularJS ?

Update:

Here is OPTIONS request:

enter image description here

Review and Response tabs are empty

Update 2:

All works fine in IE, but doesn't work in Chrome.

6
usually .Net will send error information along with its 405 status code... did you get any?Scott Selby
i have updated my question and add screen of this request in Chrome.demas
no, see in the update image you posted, check the "preview" tabScott Selby
Preview and Response tabs are emptydemas
try setting all parameters in our WCF function to optional. Let me know what that doesScott Selby

6 Answers

25
votes

I want to show what work for me.

First you must enable CORS on web.config (like Mihai sad):

<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Headers" value="Content-Type" />
    <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE,     OPTIONS" />
  </customHeaders>
</httpProtocol>

If you have some extra HEADER parameter, you must add it to Access-Control-Allow-Headers, like:

<add name="Access-Control-Allow-Headers" value="Content-Type, X-Your-Extra-Header-Key" />

And finally, to handle OPTIONS requests you must reply with empty response, adding in your application class:

protected void Application_BeginRequest()
{
    if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
    {
        Response.Flush();
    }
}
7
votes

Looks like I have found solution. I just added second method:

[<OperationContract>]    
[<WebInvoke(UriTemplate = "PostTest", 
        RequestFormat= WebMessageFormat.Json,   
        ResponseFormat = WebMessageFormat.Json, Method = "POST")>]         
abstract PostTest: obj: Test -> unit

[<OperationContract>]    
[<WebInvoke(UriTemplate = "PostTest", 
        RequestFormat= WebMessageFormat.Json,   
        ResponseFormat = WebMessageFormat.Json, Method = "OPTIONS")>]         
abstract PostTestOptions: unit -> unit

It is just empty methods that do nothing. I don't know the reason, but all is working.

2
votes

Although this already has an answer, but heres my solution. In the web config you have to remove the instruction to <remove name="OPTIONSVerbHandler" />

First add in the customHeaders

<httpProtocol>
  <!-- THESE HEADERS ARE IMPORTANT TO WORK WITH CORS -->
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Methods" value="POST, PUT, DELETE, GET, OPTIONS" />
    <add name="Access-Control-Allow-Headers" value="content-Type, accept, origin, X-Requested-With, X-Authentication, name" />
  </customHeaders>
</httpProtocol>

Then either comment out or delete the instruction to remove the OPTIONSverbHandler

<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>
0
votes

Since IIS Team published IIS CORS module hacks like empty methods are not needed anymore. It deals with CORS including preflight requests properly. You can configure it in the web config for example:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <cors enabled="true" failUnlistedOrigins="true">
            <add origin="*" />
            <add origin="https://*.microsoft.com"
                 allowCredentials="true"
                 maxAge="120"> 
                <allowHeaders allowAllRequestedHeaders="true">
                    <add header="header1" />
                    <add header="header2" />
                </allowHeaders>
                <allowMethods>
                     <add method="DELETE" />
                </allowMethods>
                <exposeHeaders>
                    <add header="header1" />
                    <add header="header2" />
                </exposeHeaders>
            </add>
            <add origin="http://*" allowed="false" />
        </cors>
    </system.webServer>
</configuration>
0
votes

I have just solved the same problem with deleting xhr.setRequestHeader() in my AJAX request. If someone has one in code, try to remove it.

0
votes

Solution that worked for me:

  1. Add this to web.config (server-side):

     <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Headers" value="Content-Type" />
        <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE,  OPTIONS" />
      </customHeaders>
    </httpProtocol>
    
  2. Create a Global.asax file (Global application class) and add the following code:

        protected void Application_BeginRequest(object sender, EventArgs e){
            if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
                {
                    Response.Flush();
                }
        }