79

I have client and a server running on different ports. The server is running Web API 2 (v5.0.0-rc1).

I tried installing the Microsoft ASP.NET Web API Cross-Origin Support package and enabled it in WebApiConfig.cs. It gives me the EnableCors() function, so the package was installed correctly.

Here you can see my Register() function in WebApiConfig.cs:

public static void Register(HttpConfiguration config)
{
    config.MapHttpAttributeRoutes();

    var cors = new EnableCorsAttribute("*", "*", "*");
    config.EnableCors(cors);
}

GET requests work fine. But when sending POST, I get the following:

OPTIONS http://localhost:19357/api/v1/rooms? 404 (Not Found) angular.js:10159
OPTIONS http://localhost:19357/api/v1/rooms? Origin http://localhost:8000 is not allowed by Access-Control-Allow-Origin. angular.js:10159
XMLHttpRequest cannot load http://localhost:19357/api/v1/rooms. Origin http://localhost:8000 is not allowed by Access-Control-Allow-Origin.

According to Fiddler it only sends the OPTIONS request. It doesn't issue the POST afterwards.

So I'm guessing the config.EnableCors(cors); in the WebApiConfig.cs isn't doing anything, which leads to the server denying the client/browser to send a POST request.

Do you have any idea how to solve this problem?

EDIT 05.09.13 This has been fixed in 5.0.0-rtm-130905

user692942
  • 16,398
  • 7
  • 76
  • 175
Gaui
  • 8,723
  • 16
  • 64
  • 91
  • Thanks for the question and answer that it's been fixed in 5.0.0-rtm. Where can I get the RTM version? – Jaans Oct 10 '13 at 05:54
  • 1
    `Tools -> Library Package Manager -> Package Manager Settings` and add the following URL under `Package Sources`: http://www.myget.org/F/aspnetwebstacknightly/ – Gaui Oct 14 '13 at 21:57

11 Answers11

84

CORS works absolutely fine in Microsoft.AspNet.WebApi.Cors version 5.2.2. The following steps configured CORS like a charm for me:

  1. Install-Package Microsoft.AspNet.WebApi.Cors -Version "5.2.2" // run from Package manager console
  2. In Global.asax, add the following line: BEFORE ANY MVC ROUTE REGISTRATIONS

    GlobalConfiguration.Configure(WebApiConfig.Register);
    
  3. In the WebApiConfig Register method, have the following code:

    public static void Register(HttpConfiguration config)
    {
        config.EnableCors();
        config.MapHttpAttributeRoutes();
    }
    

In the web.config, the following handler must be the first one in the pipeline:

<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />

In the controller derived from ApiController, add the EnableCorsAttribute:

[EnableCors(origins: "*", headers: "*", methods: "*")] // tune to your needs
[RoutePrefix("")]
public class MyController : ApiController

That should set you up nicely!

shA.t
  • 16,580
  • 5
  • 54
  • 111
Sudhanshu Mishra
  • 6,523
  • 2
  • 59
  • 76
  • Like I said it was fixed in 5.0.0-rtm-130905 :) – Gaui Dec 08 '14 at 15:51
  • Sure, I just added the steps for completeness :) – Sudhanshu Mishra Dec 09 '14 at 05:03
  • 3
    Just wanted to add, I wanted CORS enabled, but only at the controller\Action level. I didn't want it open globally. But nothing worked until I added just the config.EnableCors() in the WebApiConfig.... Basically enable it but with 0 params. But then it let me use [System.Web.Http.Cors.EnableCors(origins: "*", headers: "*", methods: "*")] at the individual Controller\Action levels. – da_jokker Feb 23 '17 at 22:31
  • how can we do this with .net 4.6.2 ? – Alex Gordon Jun 03 '18 at 03:10
  • I am using ajax call to web api 2 and I am using same above code in web api project which is running in my local. seen it is not working. – user7125929 Apr 17 '19 at 13:50
  • @user7125929 could you please elaborate on what is not working? – Sudhanshu Mishra Apr 18 '19 at 03:29
  • If you want to apply globally, you can put config.EnableCors("\*","\*","\*"); in WebApiConfig and then not need the declaration at Controller. Also web.config setting it is very much required for it to work (I just got that error :)). – Kat Lim Ruiz May 16 '19 at 14:59
  • don't forget to add using System.Web.Http.Cors; – AIMEN BOULAHIA Dec 20 '21 at 12:56
  • I had to remove ExtensionlessUrlHandler-Integrated-4.0 before adding it again. So this worked for me - – Rohit Singh Dec 02 '22 at 23:40
66

I didn't need to install any package. Just a simple change in your WebAPI project's web.config is working great:

<system.webServer>
    <httpProtocol>
        <customHeaders>
            <add name="Access-Control-Allow-Origin" value="*" />
        </customHeaders>
    </httpProtocol>
</system.webServer>

Credit goes to: Using CORS in ASP.NET WebAPI Without Being a Rocket Scientist

Mosharaf Hossain
  • 1,439
  • 12
  • 7
  • 5
    That does the trick, but it does not work if you want to specify CORS on a controller/route basis. – Gaui Nov 07 '15 at 17:11
  • 2
    As you are suggesting the same trick i used for my project, +1! And hate the nuget package, its completely unnecessary !Happy Coding bro! – Kevin Simple Apr 11 '16 at 01:43
  • 1
    Here's another caveat for this approach: With OWIN/Katana, you may not be hosting in IIS, in which case, there's no web.config - That's why the Microsoft.AspNet.WebApi.Cors package is the way to go. – Sudhanshu Mishra Feb 08 '17 at 05:01
  • 3
    Another downside of this approach is it causes the header to be included in _every_ response from your server. Microsoft.AspNet.WebApi.Cors knows to include it only when the request contains the Origin: header. – Tyler Apr 24 '17 at 14:31
  • It seems the simplest, but doesn't always work, like all cors approaches. – Svend Nov 16 '17 at 12:07
11

For reference using the [EnableCors()] approach will not work if you intercept the Message Pipeline using a DelegatingHandler. In my case was checking for an Authorization header in the request and handling it accordingly before the routing was even invoked, which meant my request was getting processed earlier in the pipeline so the [EnableCors()] had no effect.

In the end found an example CrossDomainHandler class (credit to shaunxu for the Gist) which handles the CORS for me in the pipeline and to use it is as simple as adding another message handler to the pipeline.

public class CrossDomainHandler : DelegatingHandler
    {
        const string Origin = "Origin";
        const string AccessControlRequestMethod = "Access-Control-Request-Method";
        const string AccessControlRequestHeaders = "Access-Control-Request-Headers";
        const string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
        const string AccessControlAllowMethods = "Access-Control-Allow-Methods";
        const string AccessControlAllowHeaders = "Access-Control-Allow-Headers";

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            bool isCorsRequest = request.Headers.Contains(Origin);
            bool isPreflightRequest = request.Method == HttpMethod.Options;
            if (isCorsRequest)
            {
                if (isPreflightRequest)
                {
                    return Task.Factory.StartNew(() =>
                    {
                        HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
                        response.Headers.Add(AccessControlAllowOrigin, request.Headers.GetValues(Origin).First());

                        string accessControlRequestMethod = request.Headers.GetValues(AccessControlRequestMethod).FirstOrDefault();
                        if (accessControlRequestMethod != null)
                        {
                            response.Headers.Add(AccessControlAllowMethods, accessControlRequestMethod);
                        }

                        string requestedHeaders = string.Join(", ", request.Headers.GetValues(AccessControlRequestHeaders));
                        if (!string.IsNullOrEmpty(requestedHeaders))
                        {
                            response.Headers.Add(AccessControlAllowHeaders, requestedHeaders);
                        }

                        return response;
                    }, cancellationToken);
                }
                else
                {
                    return base.SendAsync(request, cancellationToken).ContinueWith(t =>
                    {
                        HttpResponseMessage resp = t.Result;
                        resp.Headers.Add(AccessControlAllowOrigin, request.Headers.GetValues(Origin).First());
                        return resp;
                    });
                }
            }
            else
            {
                return base.SendAsync(request, cancellationToken);
            }
        }
    }

To use it add it to the list of registered message handlers

config.MessageHandlers.Add(new CrossDomainHandler());

Any preflight requests by the Browser are handled and passed on, meaning I didn't need to implement an [HttpOptions] IHttpActionResult method on the Controller.

user692942
  • 16,398
  • 7
  • 76
  • 175
  • 1
    This put me onto an issue I was having with ASP .NET Web API CORS policies where the relevant responses don't kick come back. Turns out it is a FilterAttribute based implementation and doesn't participate as early as the ```DelegatingHandler``` phase of the pipeline. So if a handler returns early, you'd have to provide a CORS header response manually (and as per your policies). – Jaans Jul 09 '18 at 02:18
7

I'm most definitely hitting this issue with attribute routing. The issue was fixed as of 5.0.0-rtm-130905. But still, you can try out the nightly builds which will most certainly have the fix.

To add nightlies to your NuGet package source, go to Tools -> Library Package Manager -> Package Manager Settings and add the following URL under Package Sources: http://myget.org/F/aspnetwebstacknightly

Gaui
  • 8,723
  • 16
  • 64
  • 91
7

Make sure that you are accessing the WebAPI through HTTPS.

I also enabled cors in the WebApi.config.

var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);

But my CORS request did not work until I used HTTPS urls.

tno2007
  • 1,993
  • 25
  • 16
5

This solved my issue:

in Web.config>>Inside system.webServer tags:

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

And uncomment or delete this line inside system.webServer:

<remove name="OPTIONSVerbHandler"/>

Also, you need to declare enable cors either in webapiconfig.cs or in web.config. If you declare in both you may get an error something like :

'....origin 'www.example.com' blocked by cors policy due to multiple No 'Access-Control-Allow-Origin'('*','*').'

This did the trick for me.

krish
  • 237
  • 4
  • 14
4

Late reply for future reference. What was working for me was enabling it by nuget and then adding custom headers into web.config.

Mariusz
  • 908
  • 1
  • 13
  • 28
  • Thanks! Installing via the package manage console just wasn't working for me, so I tried it via NuGet interface and it updated the project references automatically and works fine now. – user441058 Jun 10 '15 at 21:25
4
 var cors = new EnableCorsAttribute("*","*","*");
 config.EnableCors(cors);

 var constraints = new {httpMethod = new HttpMethodConstraint(HttpMethod.Options)};
 config.Routes.IgnoreRoute("OPTIONS", "*pathInfo",constraints);
Vikas
  • 158
  • 15
1

To enable CORS, 1.Go to App_Start folder. 2.add the namespace 'using System.Web.Http.Cors'; 3.Open the WebApiConfig.cs file and type the following in a static method.

config.EnableCors(new EnableCorsAttribute("https://localhost:44328",headers:"*", methods:"*"));
0

As far as I understood, the server got to have a header that specifies that Access from Origin is Allowed i.e. a request from the same server could be responded to.

I used the following code :

// create a response object of your choice
var response = Request.CreateResponse(HttpStatusCode.OK);

//add the header
//replace the star with a specific name if you want to restrict access
response.Headers.Add("Access-Control-Allow-Origin", "*");

//now you could send the response and it should work...
return response;
Jitin
  • 346
  • 3
  • 13
0

Below code worked for me,

App_Start -> WebApiConfig

EnableCorsAttribute cors = new EnableCorsAttribute("\*", "\*", "GET,HEAD,POST");
config.EnableCors(cors);
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103