2

I am making delete requests from an AngularJS app to an asp.net web api and I am getting below error -

XMLHttpRequest cannot load http://api.prod.com/api/v1/proddetails/34. No   
'Access-Control-Allow-Origin' header is present on the requested resource. 
Origin 'http://localhost:5100' is therefore not allowed access. The response     
had HTTP status code 403.

Method:

[HttpDelete]
public HttpResponseMessage Delete(int id)

Web Config:

<system.webServer>
<validation validateIntegratedModeConfiguration="false" />

<modules runAllManagedModulesForAllRequests="true">
  <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
  <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />
  <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
  <remove name="WebDAVModule" />
</modules>

<security>
  <requestFiltering>
    <requestLimits maxAllowedContentLength="12582912" />
    <!--12 MB-->
  </requestFiltering>
</security>
<handlers>
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <remove name="OPTIONSVerbHandler" />
  <remove name="TRACEVerbHandler" />
  <remove name="WebDAV" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>

Please help.

Note: The machine is a Windows Server 2012 R2 running IIS 8.5 on AWS EC2. I have CORS setup properly like this on the controller -

[EnableCors(origins: "*", headers: "*", methods: "*")]

Edit1:

I was looking at my applicationHost.config file, and it has these lines -

<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="C:\windows\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="C:\windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />

But there are so many of them, and none of them have DELETE as allowed verb. Can this be causing an issue?

Edit2:

As requested, this is the AngularJS request code -

$http.delete('http://api.prod.com/api/v1/proddetails/' + data)
                .success(function (data, status, headers, config) {
                    console.log(data);
                    if(data.status == "200")
                    {
                        console.log('data deleted');
                    }
                    deferred.resolve(data);
                })
                .error(function (data, status, headers, config) {
                    console.log("some error occurred");
                    deferred.reject(data);
                });
Sam
  • 4,302
  • 12
  • 40
  • 74
  • probably you are getting a 500 internal server error for some other reason, try investigate better what happens on server, sometimes the 'Access-Control-Allow-Origin' error is misleading – JackNova Mar 23 '15 at 20:49
  • I tried the same code on my localhost and it works, but fails on production. OPTIONS request is 200 OK but DELETE request is 403 Access Denied on production. – Sam Mar 23 '15 at 20:50
  • I am thinking it is related to this - http://blogs.msdn.com/b/tmarq/archive/2010/05/26/how-extensionless-urls-are-handled-by-asp-net-v4.aspx – Sam Mar 23 '15 at 20:54
  • the difference could be the model in your local environment differs from the production one, so, in production you don't have privileges to delete the record – JackNova Mar 23 '15 at 21:04
  • The request is even not hitting the endpoint. I am the admin of both local and prod and have provided all access. I am thinking as the prod is on AWS EC2, there might be some firewall problems. – Sam Mar 23 '15 at 21:05

3 Answers3

0

Try changing this property of Web.config:

   <add name="ExtensionlessUrl-Integrated-4.0" 
       path="*." 
       verb="GET,HEAD,POST,DEBUG,DELETE,PUT" 
       type="System.Web.Handlers.TransferRequestHandler" 
       preCondition="integratedMode,runtimeVersionv4.0" />
manzapanza
  • 6,087
  • 4
  • 39
  • 48
0

Two things could be going on here.

First

In IIS if you click at the root most node (computer name), you can see under management in the right frame an icon called Feature Delegation. Open that by double clicking it. From within there, you will see a list of delegations, find Handler Mappings and make sure it is set to read/write. This will allow the site to override the default handlers that may not be allowing the DELETE verb. Then make sure the web.config reflects the verbs you want to be enabled for extensionlessurlhandler.

Second

You must implement the options verb on your API controllers like this:

[HttpOptions, AllowAnonymous]
public IHttpActionResult Options()
{
    return StatusCode(HttpStatusCode.OK);
}

this is because CORS will "pre-flight" many requests that are not a simple get or post.

from the mozilla docs on the subject:

Preflighted requests

Unlike simple requests (discussed above), "preflighted" requests first send an HTTP request by the OPTIONS method to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests are preflighted like this since they may have implications to user data. In particular, a request is preflighted if:

It uses methods other than GET, HEAD or POST. Also, if POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, e.g. if the POST request sends an XML payload to the server using application/xml or text/xml, then the request is preflighted.

It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)

Also, localhost may have issues with CORS. There are workarounds to develop with, see:

Deadly CORS when http://localhost is the origin

Community
  • 1
  • 1
Mark
  • 356
  • 1
  • 5
  • It doesnt explain why GET and POST are working and DELETE not. As POST also sends the pre-flight request. Please see Edit1. – Sam Mar 23 '15 at 19:13
  • I don't think your edit is the issue. Post only sends a pre-flight under certain conditions. Have you implemented the options verb? If not it will be required regardless so we should try that. – Mark Mar 23 '15 at 19:16
  • can you watch the requests with fiddler? it would be good to know what is being sent and when the error is really coming back, as it could come from either the options or the delete method. Also the anonymous part of the options method is important, it won't send authentication to that – Mark Mar 23 '15 at 19:19
  • OPTIONS request is 200 OK, with Access-Control-Request-Header:accept, authorization and Access-Control-Request-Method: DELETE. But actual DELETE request throws 403 Access Denied. – Sam Mar 23 '15 at 19:28
  • can you post the javascript of the request? – Mark Mar 23 '15 at 19:39
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/73612/discussion-between-mark-and-sam). – Mark Mar 23 '15 at 19:40
0

Change the following tag in your applicationHost.config file:

<add name="ExtensionlessUrlHandler-Integrated-4.0" 
     path="*." 
     verb="GET,HEAD,POST,DEBUG, DELETE" 
     type="System.Web.Handlers.TransferRequestHandler" 
     preCondition="integratedMode,runtimeVersionv4.0" 
     responseBufferLimit="0" />
Paul Roub
  • 36,322
  • 27
  • 84
  • 93