28

I'm having a lot of trouble getting a cross domain POST request to hit an Api controller in the latest beta 2 release.

Chrome (and other browsers) spit out:

OPTIONS http://api.hybridwebapp.com/api/values 400 (Bad Request)
POST http://api.hybridwebapp.com/api/values 404 (Not Found) 

It may be related to this issue but I have applied that workaround and several other fixes such as web.config additions here

I've been banging my head with this for a while so I created a solution to reproduce the problem exactly.

Load the web app there will be 2 buttons one for GET one for POST and the response will appear next to the button. GET works. Cannot get POST to return successfully.

enter image description here

I'm able to get a hint at the cause from Fiddler but it makes no sense because if you look at the response it DOES include the domain in the Access-Controll-Allow-Origin header:

enter image description here

There is a folder in the solution called "ConfigurationScreenshots" with a few screenshots of the IIS configuration (website bindings) and Project properties configurations to make it as easy as possible to help me :)

EDIT: Don't forget to add this entry to host file (%SystemRoot%\system32\drivers\etc):

 127.0.0.1     hybridwebapp.com  api.hybridwebapp.com

**STATUS: ** It seems that some browsers like Chrome allow me to proceed with the POST regardless of the error message in the OPTIONS response (while others like Firefox don't). But I don't consider that solved.

Look at the Fidler screenshots of the OPTIONS request it has

Access-Control-Allow-Origin: http://hybridwebapp.com

And yet the error:

The origin http://hybridwebapp.com is not allowed

That is completely contradictory it's as if it's ignoring the header.

Community
  • 1
  • 1
parliament
  • 21,544
  • 38
  • 148
  • 238
  • Can you include the headers for the POST request as well? The preflight is also weird: It is returning a 400 with an error message in the body, but it also returns the correct CORS headers, so the preflight succeeds (as evidenced by the fact that it is followed by a POST request). – monsur Jul 18 '13 at 02:45
  • Added. Thanks for taking a look. – parliament Jul 18 '13 at 04:02
  • 1
    I believe you could be facing a known issue which was fixed after beta. The following bug's comment has the link to the fix:http://aspnetwebstack.codeplex.com/workitem/1050 – Kiran Jul 18 '13 at 04:09
  • Thanks, yes that looks like it's probably the solution. How exactly do I apply the fix, I've never did this I always use nuget? I tried opening the source in VS, building, then referencing the newly compiled System.Web.Cors.dll and System.Web.Http.Cors.dll but my application throws the exception: `Could not load file or assembly 'System.Web.Cors' or one of its dependencies. Strong name signature could not be verified. The assembly may have been tampered with, or it was delay signed but not fully signed with the correct private key. ` – parliament Jul 18 '13 at 04:47
  • 1
    I would suggest to NOT get the latest nightly builds as there have been some code changes which can break you. I would instead suggest you to create a custom provider factory which is just a copy of the `AttributeBasedPolicyProviderFactory` having the fix and then do something like `config.SetCorsPolicyProviderFactory(your-custom-provider-factory-here);`...this should most probably fix your issue.. – Kiran Jul 18 '13 at 05:15
  • This did work although the OPTIONS request still returns 400 with the same message about origin not allowed, the following POST request DOES successfully hit the controller but returns with 204... It doesn't seem like a full fix but at least I can hit the controller and proceed. Please make an answer and I will accept since it's the best answer there is currently :) – parliament Jul 18 '13 at 17:54
  • The answer at this post: [http://stackoverflow.com/questions/26447766/angular-js-resource-with-asp-net-webapi/40476557#40476557](http://stackoverflow.com/questions/26447766/angular-js-resource-with-asp-net-webapi/40476557#40476557) – Ibere Spadoto Nov 07 '16 at 23:56

5 Answers5

24

Ok I got past this. This has got to be the strangest issue I've ever encountered. Here's how to "solve" it:

  1. Continue on with life as usual until suddenly out of no where OPTIONS requests to this domain begin returning 200 OK (instead of 400 Bad Request) and POST never happens (or at least seems like it doesn't because the browser swallows it)
  2. Realize that Fiddler's OPTIONS response mysteriously contains duplicates for "Access-Control-Allow-XXX".
  3. Try removing the following statement from you web.config even though you clearly remember trying that to fix the previous issue and it not working:

Remove this:

    <httpProtocol>
       <customHeaders>
         <remove name="X-Powered-By" />
         <add name="Access-Control-Allow-Origin" value="http://mydomain.com" />
         <add name="Access-Control-Allow-Headers" value="Accept, Content-Type, Origin" />
         <add name="Access-Control-Allow-Methods" value="GET, PUT, POST, DELETE, OPTIONS" />
       </customHeaders>
    </httpProtocol>

Because you already have this:

 var enableCorsAttribute = new EnableCorsAttribute("http://mydomain.com",
                                                   "Origin, Content-Type, Accept",
                                                   "GET, PUT, POST, DELETE, OPTIONS");
        config.EnableCors(enableCorsAttribute);

Moral: You only need one.

parliament
  • 21,544
  • 38
  • 148
  • 238
  • For Web API with OWINS, we can use the OAuthAuthorizationServerProvider to handle the preflight and actual requests. This should be the only area to add the headers based on the Origin value (if allowed) for more information see this article: http://www.ozkary.com/2016/04/web-api-owin-cors-handling-no-access.html – ozkary Apr 12 '16 at 18:15
  • I had an attribute [AllowCrossSiteJson] which was doing my CORS headers, but while working on something else, I added OWin.Cors - your post put me on the right track! – agrath Jun 05 '17 at 04:19
12

if you use OAuth Authorization . request not go direct to web api. You need to enable OWIN CORS support for that endpoint.

How i do on my site: Install owin cors

Install-Package Microsoft.Owin.Cors

Note: please not use : Install-Package Microsoft.AspNet.WebApi.Cors

In file Startup.Auth.cs

 //add this line
            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

            // Enable the application to use bearer tokens to authenticate users
            app.UseOAuthBearerTokens(OAuthOptions);
Wolf
  • 6,361
  • 2
  • 28
  • 25
  • Why should one not use Microsoft.AspNet.WebApi.Cors? What's the difference between the two packages? – LavaHot Sep 14 '15 at 20:54
  • 2
    Ask i understand, Microsoft.Owin.Cors is allow cors for all (webapi, mvc control...), WebApi.Cors is setting only for WebApi. – Wolf Oct 16 '15 at 03:11
3

I have an MVC controller (not an ApiController) but the solution I came up with may help others. To allow cross domain access to a POST action (/data/xlsx) on the controller I implemented 2 actions:

  1. for the pre-flight check
  2. for the post

If you don't have the HttpOptions action then you get 404's on the pre-flight check.

Code:

[HttpOptions]
public ActionResult Xlsx()
{
    // Catches and authorises pre-flight requests for /data/xlsx from remote domains
    Response.AddHeader("Access-Control-Allow-Origin", "*");
    Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    Response.AddHeader("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS");
    return null;
}

[HttpPost]
public ActionResult Xlsx(string data, string name)
{
    Xlsx(); // Add CORS headers

    /* ... implementation here ... */
}

I've tested it in IE 11, Chrome, FireFox.

Ilan
  • 1,647
  • 1
  • 15
  • 16
  • 1
    Downvoted. Use filters and use MVC/Web Api how it's designed to use. Don't add request header information inside an action. – Frederik Prijck Jun 17 '16 at 07:54
  • To be more specific why I downvoted this: Use a filter when you want to modify the Request / Response pipeline. This keeps your controller actions clean and ensures a Separation of Concerns throughout your application. Secondly, why you would want to use CORS in MVC is also discussable, Web Api is more fit for pure content-serving. There is a reason why docs on CORS for MVC are limited. For Web Api look at the Enable Cors Filter and http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api and https://docs.asp.net/en/latest/security/cors.html#setting-up-cors – Frederik Prijck Jun 20 '16 at 06:50
  • Read up on filters, every call to the AddHeader method can be removed from the controller action resulting in the exact same behavior but cleaner controllers. The cors code will also be reusable throughout your entire application. But as you know what you're doing, I won't try to convince you any further. Bit weird that you're wandering around on a forum and don't want people to give you any advice ?You're answer is 100% not as how MVC wants it. I don't mind that you don't care, but don't provide it as an answer on a public forum as it's not valid for proper MVC development. – Frederik Prijck Jul 05 '16 at 12:47
  • Here's what I mean, even if you don't care others will care why ur solution is not conform MVC. I am not talking about whether or not this is the way cors is to be activated, but the actual code realy isn't okay. Gist: https://gist.github.com/frederikprijck/22b59541cdab32ac5fdda1a060621587 Http header results for : Your solution: http://prntscr.com/bp2k3n, Using Filters: http://prntscr.com/bp2k8p – Frederik Prijck Jul 05 '16 at 13:13
  • Evenmore, the HttpOptions method shouldn't be neccesary, resulting in: https://gist.github.com/frederikprijck/72f1f02d3e379f976f5e23de7dcd3d2a. With the following HTTP Headers: http://prntscr.com/bp2txy – Frederik Prijck Jul 05 '16 at 13:33
  • U're saying: "If you bothered to try this stuff yourself ... ".. I never said Ur code is not working. I said it's not done as it should be In MVC. If you take a look at my samples above, you'll see that I'm still using the exact same 3 lines which you were using. For Web Api there are built in solutions which don't require manually altering the Http Headers. As the OP asked for Web Api I stll think you're reply is incorrect..With a few modifications, your solution can be valid for MVC, but that still doesn't make it an answer for this question. – Frederik Prijck Jul 05 '16 at 13:49
  • 1
    In fact I'm not even sure whether yours will work. From what I remember CORS request actually comes as 2 requests - the pre-flight OPTIONS check, and the actual request. You can't return the File() result in the first request with some `Access-Control` header options set so you can't just drop the HttpOptions method. – Ilan Jul 05 '16 at 14:06
  • This was the solution for me. even after i allow cors on filter - for some reson the request didnt pass to the post from angular 7 until i open another OPTIONS method. – Zvi Redler Mar 18 '19 at 12:53
2

Add this to your startup.cs file inside ConfigureOAuth

app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

Mohsin Muzawar
  • 1,202
  • 9
  • 9
0

Try to add below code in your Response header:

Response.AddHeader("Access-Control-Allow-Origin", "*");
Wilson Wu
  • 1,790
  • 19
  • 13