I am making the following request to an asp.net web api PUT method from my angular.js client:
var org = {
OrgId: 111,
nam
Yep, an oldie but a goodie. I had the same problem and symptom but my resolution was self-inflicted. I'll share it anyway. The way our service configured the controller used in all of the MapHttpRoute
calls at startup included the [DisableCors]
attribute. As soon as I reconfigured my local machine startup to use a different controller, everything worked. So if you've done everything else listed here then check your controller and make sure you didn't do something stupid, like I did.
This is almost certainly a CORS problem. I'd first read up about it to make sure you understand what this is and why it is important. And I would guess that your server configuration is not correct.
Unfortunately, I don't know much about .net, but this CORS tutorial for .net describes what you should do quite clearly.
It looks like you are missing an EnableCors
annotation. It looks like you need to add something like [EnableCors("*", "*", "*")]
to your controller. Explicit handling of OPTIONS is not necessary. Of course, in producition, you don't want to use wildcards for your CORS handling. They should be more specific, but this is fine for testing.
Apparently, in certain cases, an OPTIONS request is sent before the "real" request to determine whether the real request is safe to send due to CORS. See the following MS article at: http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api and search for "Preflight Requests".
Some of the following Q&As might also help:
I know this is an old question, but I ran into the same problem and figured I could help others who are trying to figure out.
I solved it by removing 2 of the handler configurations in the Web.config:
<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>
I don't know exactly why it fixed the problem, but my working theory is that <remove name="OPTIONSVerbHandler" />
makes OPTIONS requests forbidden by default. When sending the request from a browser, it sends an OPTIONS request first before the PUT request, so it never gets to the PUT request because the first OPTIONS request was denied as an invalid http method on the api.
In fiddler, I am assuming that it just sends only the PUT request (I observed the same behavior using the Postman web app sending requests manually). So it skips the forbidden OPTIONS request and succeeds.
Andrew is correct, it is most probably a CORS issue. What you need is to add EnableCors
attribute to your Controller class so that is looks something like this
[EnableCors(origins: "https://example.com,http://example.org", headers: "*", methods: "*")]
public class TestController : ApiController
{
// your code
The other way to do this is mentioned in this stack overflow post
I also faced the same issue, after few research, I did following changes to web.config and Global.asax.cs files
<configuration>
<system.webServer>
<directoryBrowse enabled="true" />
<validation validateIntegratedModeConfiguration="false" />
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, PATCH, DELETE, OPTIONS" />
<add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
</customHeaders>
</httpProtocol>
<handlers>
<remove name="WebDAV" />
<remove name="OPTIONSVerbHandler"/>
<remove name="TRACEVerbHandler" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" 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,PUT,DELETE,PATCH,OPTIONS" 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,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
<modules runAllManagedModulesForAllRequests="true">
<remove name="WebDAVModule" />
<remove name="ApplicationInsightsWebTracking" />
<add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" preCondition="managedHandler" />
</modules>
</system.webServer>
</configuration>
Add the following code global.ascx.cs
protected void Application_BeginRequest()
{
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}