7

The problem:

For some reason, when enabling CORS, the Access-Control-Allow-Origin header is not included in the response.

The error:

Access to XMLHttpRequest at 'https://.../api/endpoints/some-path' from origin 'https://some.site.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Configuration (.NET MVC 5)

web.config headers:

<system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="Access-Control-Allow-Credentials" value="true"/>
      <add name="Access-Control-Allow-Headers" value="Content-Type" />
      <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, OPTIONS" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

Web API config:

config.EnableCors();

API endpoint:

[RoutePrefix("api/endpoints")]
[EnableCors(origins: "https://some.site.com", headers: "*", methods: "*")]
public class MyApiController : ApiController
{
    [HttpPost]
    [Route("some-path")]
    [EnableCors(origins: "https://some.site.com", headers: "*", methods: "*")]
    public ResponseModel GetSomeResponse(DataModel model) { ... }
}

global.asax.cs

protected void Application_BeginRequest(object sender, EventArgs e)
{
    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
        HttpContext.Current.Response.Flush();
}

The only way I can get successfully get the application to return that header is to explicitly include it as a custom header in the web.config:

<add name="Access-Control-Allow-Origin" value="https://some.site.com" />
sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
ianpoley
  • 552
  • 2
  • 10
  • 20

7 Answers7

0

Add same method with HttpOptions header and same route name. Browser will send preflight request to your controller. Which means Options method will be triggered to access header informations of the server.

[HttpOptions]
[Route("some-path")]
[EnableCors(origins: "https://some.site.com", headers: "*", methods: "*")]
public ResponseModel GetSomeResponse(DataModel model) { ... }
Berkay Yaylacı
  • 4,383
  • 2
  • 20
  • 37
0

From: https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api

Confirm that the Access-Control-Request-Method and Access-Control-Request-Headers headers are sent with the request and that OPTIONS headers reach the app through IIS.

To configure IIS to allow an ASP.NET app to receive and handle OPTION requests, add the following configuration to the app's web.config file in the <system.webServer> section:

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

The removal of OPTIONSVerbHandler prevents IIS from handling OPTIONS requests. The replacement of ExtensionlessUrlHandler-Integrated-4.0 allows OPTIONS requests to reach the app because the default module registration only allows GET, HEAD, POST, and DEBUG requests with extensionless URLs.

Nitin Sawant
  • 7,278
  • 9
  • 52
  • 98
0

This is working for me. Handling pre-flight request and cors Web.config

<system.webServer>   
    <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>
  </system.webServer>

Global.asax.cs

protected void Application_BeginRequest(object sender, EventArgs e)
        {
            if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
            {
                //These headers are handling the "pre-flight" OPTIONS call sent by the browser
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "*"); // For All HttpVerb
                //HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
                //HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "*");
                //HttpContext.Current.Response.AddHeader("Access-Control-Allow‌​-Credentials", "true");
                HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "600");//1728000
                HttpContext.Current.Response.StatusCode = 204;

                HttpContext.Current.Response.End();
            }
        }

WebApiConfig.cs

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

Add Attribuites in your controller

[EnableCors(origins: "*", headers: "*", methods: "*")]
Biju Kalanjoor
  • 532
  • 1
  • 6
  • 12
0

Always try to keep your code simple and clear if possible.

Actually, There's no need to change the web.config, controllers or global.asax.cs. So clean them and Just use the following configuration inside Configure method in Startup.cs file :

app.UseExceptionHandler(builder =>
{
    builder.Run(
    async context =>
    {
        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
        context.Response.Headers.Add("Access-Control-Allow-Origin", "*");

        var error = context.Features.Get<IExceptionHandlerFeature>();
        if (error != null)
        {
            context.Response.AddApplicationError(error.Error.Message);
            await context.Response.WriteAsync(error.Error.Message).ConfigureAwait(false);
        }
    });
});

Where ResponseExtensions is defined as extension with the following details:

public static class ResponseExtensions
{
    public static void AddApplicationError(this HttpResponse response, string message)
    {
        response.Headers.Add("Application-Error", message);
        // CORS
        response.Headers.Add("access-control-expose-headers", "Application-Error");
    }
}

This is working fine in my fully API-based Asp.net project.

Amirhossein Mehrvarzi
  • 18,024
  • 7
  • 45
  • 70
-1

Set CORS globally for all the controllers. Inside WebApiConfig class, Create the instance of EnableCorsAttribute and use in EnableCors method as:

var cors = new EnableCorsAttribute("https://some.site.com", "*", "*");
config.EnableCors(cors);
Sh.Imran
  • 1,035
  • 7
  • 13
  • This works, but has the same effect as adding it in the web.config. I would like to have more fine-grained control over CORS policy on a per-API or endpoint basis and not set it as the same value for all requests. – ianpoley Jul 30 '20 at 19:57
  • If you want to implement CORS as per-API basis then apply this attribute on method attribute instead of controller level: `[EnableCors(origins: "https://some.site.com", headers: "*", methods: "*")]` – Sh.Imran Jul 30 '20 at 20:04
  • Yes, that's mentioned in the original post. Adding the attribute does not result in an `Access-Control-Allow-Origin` header being added to the response. – ianpoley Jul 30 '20 at 20:13
  • But in the original post, you have applied it controller level. Remove from controller and apply only on method. – Sh.Imran Jul 30 '20 at 20:15
  • You're right, I've edited it to make it clear I've tried both approaches. Thanks for pointing that out. – ianpoley Jul 30 '20 at 20:21
  • Try with http instead of https – Sh.Imran Jul 30 '20 at 20:33
  • No dice with either http or https. – ianpoley Jul 30 '20 at 20:38
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/218936/discussion-between-imran-and-ianpoley). – Sh.Imran Jul 30 '20 at 21:01
-1

Globally Enable CORS The method described can also be used to enable CORS across the API without annotating each controller as per below in WebApiConfig

public static void Register(HttpConfiguration config)
{
    var corsAttr = new EnableCorsAttribute("http://example.com", "*", "*");
    config.EnableCors(corsAttr);
}
  • Hello and welcome to the StackOverflow. If you can provide more detail about the code, it would be a better answer, here is a tip: https://stackoverflow.com/help/how-to-answer – Ali Kianoor Aug 20 '20 at 12:38
  • You are correct, but that does not solve my issue. I need to be able to set different `Access-Control-Allow-Origin` on a per-endpoint basis. – ianpoley Aug 20 '20 at 18:54
-1

I followed the same steps that are shared by Shaun in below post where we can enable CORS at method level. It works fine for me. Could you please try at your end?

Asp.Net WebApi2 Enable CORS not working with AspNet.WebApi.Cors 5.2.3