Asp.Net WebApi2 Enable CORS not working with AspNet.WebApi.Cors 5.2.3
I tried to follow the steps at http://enable-cors.org/server_aspnet.html to have my RESTful API (implemented with ASP.NET WebAPI2) work with cross origin requests (CORS Enabled). It's not working unless I modify the web.config.
I installed WebApi Cors dependency:
install-package Microsoft.AspNet.WebApi.Cors -ProjectName MyProject.Web.Api
Then in my App_Start
I've got the class WebApiConfig
as follows:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var corsAttr = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(corsAttr);
var constraintsResolver = new DefaultInlineConstraintResolver();
constraintsResolver.ConstraintMap.Add("apiVersionConstraint", typeof(ApiVersionConstraint));
config.MapHttpAttributeRoutes(constraintsResolver);
config.Services.Replace(typeof(IHttpControllerSelector), new NamespaceHttpControllerSelector(config));
//config.EnableSystemDiagnosticsTracing();
config.Services.Replace(typeof(ITraceWriter), new SimpleTraceWriter(WebContainerManager.Get<ILogManager>()));
config.Services.Add(typeof(IExceptionLogger), new SimpleExceptionLogger(WebContainerManager.Get<ILogManager>()));
config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());
}
}
but after that I run the application, I request a resource with Fiddler like: http://localhost:51589/api/v1/persons and in the response I cannot see the HTTP headers that I should see such as:
Access-Control-Allow-Methods: POST, PUT, DELETE, GET, OPTIONS
Access-Control-Allow-Origin: *
Am I missing some step? I have tried with the following annotation on the controller:
[EnableCors(origins: "http://example.com", headers: "*", methods: "*")]
Same result, no CORS enabled.
However, if I add the following in my web.config (without even installing the AspNet.WebApi.Cors dependency) it works:
<system.webServer>
<httpProtocol>
<!-- THESE HEADERS ARE IMPORTANT TO WORK WITH CORS -->
<!--
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="POST, PUT, DELETE, GET, OPTIONS" />
<add name="Access-Control-Allow-Headers" value="content-Type, accept, origin, X-Requested-With, Authorization, name" />
<add name="Access-Control-Allow-Credentials" value="true" />
</customHeaders>
-->
</httpProtocol>
<handlers>
<!-- THESE HANDLERS ARE IMPORTANT FOR WEB API TO WORK WITH GET,HEAD,POST,PUT,DELETE and CORS-->
<!--
<remove name="WebDAV" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,PUT,DELETE" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
<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>
Any help would be much appreciated!
Thank you.
I've created a pared-down demo project for you.
- Source: https://github.com/bigfont/webapi-cors
- Api Link: https://cors-webapi.azurewebsites.net/api/values
You can try the above API Link from your local Fiddler to see the headers. Here is an explanation.
Global.ascx
All this does is call the WebApiConfig
. It's nothing but code organization.
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
WebApiConfig.Register(GlobalConfiguration.Configuration);
}
}
WebApiConfig.cs
The key method for your here is the EnableCrossSiteRequests
method. This is all that you need to do. The EnableCorsAttribute
is a globally scoped CORS attribute.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
EnableCrossSiteRequests(config);
AddRoutes(config);
}
private static void AddRoutes(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "Default",
routeTemplate: "api/{controller}/"
);
}
private static void EnableCrossSiteRequests(HttpConfiguration config)
{
var cors = new EnableCorsAttribute(
origins: "*",
headers: "*",
methods: "*");
config.EnableCors(cors);
}
}
Values Controller
The Get
method receives the EnableCors
attribute that we applied globally. The Another
method overrides the global EnableCors
.
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] {
"This is a CORS response.",
"It works from any origin."
};
}
// GET api/values/another
[HttpGet]
[EnableCors(origins:"http://www.bigfont.ca", headers:"*", methods: "*")]
public IEnumerable<string> Another()
{
return new string[] {
"This is a CORS response. ",
"It works only from two origins: ",
"1. www.bigfont.ca ",
"2. the same origin."
};
}
}
Web.config
You do not need to add anything special into web.config. In fact, this is what the demo's web.config looks like - it's empty.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
</configuration>
Demo
var url = "https://cors-webapi.azurewebsites.net/api/values"
$.get(url, function(data) {
console.log("We expect this to succeed.");
console.log(data);
});
var url = "https://cors-webapi.azurewebsites.net/api/values/another"
$.get(url, function(data) {
console.log(data);
}).fail(function(xhr, status, text) {
console.log("We expect this to fail.");
console.log(status);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You just need to change some files. This works for me.
Global.ascx
public class WebApiApplication : System.Web.HttpApplication {
protected void Application_Start()
{
WebApiConfig.Register(GlobalConfiguration.Configuration);
} }
WebApiConfig.cs
All the requests has to call this code.
public static class WebApiConfig {
public static void Register(HttpConfiguration config)
{
EnableCrossSiteRequests(config);
AddRoutes(config);
}
private static void AddRoutes(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "Default",
routeTemplate: "api/{controller}/"
);
}
private static void EnableCrossSiteRequests(HttpConfiguration config)
{
var cors = new EnableCorsAttribute(
origins: "*",
headers: "*",
methods: "*");
config.EnableCors(cors);
} }
Some Controller
Nothing to change.
Web.config
You need to add handlers in your web.config
<configuration>
<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>
</configuration>
In case of CORS request all modern browsers respond with an OPTION verb, and then the actual request follows through. This is supposed to be used to prompt the user for confirmation in case of a CORS request. But in case of an API if you would want to skip this verification process add the following snippet to Global.asax
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "POST, PUT, DELETE");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}
Here we are just by passing the check by checking for OPTIONS verb.
I just added custom headers to the Web.config and it worked like a charm.
On configuration - system.webServer:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
</customHeaders>
</httpProtocol>
I have the front end app and the backend on the same solution. For this to work, I need to set the web services project (Backend) as the default for this to work.
I was using ReST, haven't tried with anything else.
After some modifications in my Web.config CORS suddenly stopped working in my Web API 2 project (at least for OPTIONS request during the preflight). It seems that you need to have the section mentioned below in your Web.config or otherwise the (global) EnableCorsAttribute will not work on OPTIONS requests. Note that this is the exact same section Visual Studio will add in a new Web API 2 project.
<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>