223

I have a simple actionmethod, that returns some json. It runs on ajax.example.com. I need to access this from another site someothersite.com.

If I try to call it, I get the expected...:

Origin http://someothersite.com is not allowed by Access-Control-Allow-Origin.

I know of two ways to get around this: JSONP and creating a custom HttpHandler to set the header.

Is there no simpler way?

Is it not possible for a simple action to either define a list of allowed origins - or simple allow everyone? Maybe an action filter?

Optimal would be...:

return json(mydata, JsonBehaviour.IDontCareWhoAccessesMe);
sideshowbarker
89.1k30 gold badges218 silver badges215 bronze badges
asked Jun 9, 2011 at 8:29
0

15 Answers 15

408

For plain ASP.NET MVC Controllers

Create a new attribute

public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
{
 public override void OnActionExecuting(ActionExecutingContext filterContext)
 {
 filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*");
 base.OnActionExecuting(filterContext);
 }
}

Tag your action:

[AllowCrossSiteJson]
public ActionResult YourMethod()
{
 return Json("Works better?");
}

For ASP.NET Web API

using System;
using System.Web.Http.Filters;
public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
{
 public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
 {
 if (actionExecutedContext.Response != null)
 actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
 base.OnActionExecuted(actionExecutedContext);
 }
}

Tag a whole API controller:

[AllowCrossSiteJson]
public class ValuesController : ApiController
{

Or individual API calls:

[AllowCrossSiteJson]
public IEnumerable<PartViewModel> Get()
{
 ...
}

For Internet Explorer <= v9

IE <= 9 doesn't support CORS. I've written a javascript that will automatically route those requests through a proxy. It's all 100% transparent (you just have to include my proxy and the script).

Download it using nuget corsproxy and follow the included instructions.

Blog post | Source code

answered Jun 9, 2011 at 9:00

9 Comments

in awe of the elegance of this solution
You could easily extend the attribute to accept a specific origin if you wanted to limit CORS to your own domains.
You should be able to add this to the RegisterHttpFilters in your App_Start\FilterConfig correct? Doing so would apply it to all of the Api controllers in your project. Coupling this with pate's comment above you could limit CORS to your domain(s) for all controllers.
I found this method failed with the PUT http verb. Instead I used: brockallen.com/2012/06/28/…
I've recently updated our project to MVC 5 and attempted to do this. Even adding the header in a filter doesn't seem to work. When I view the request in network the header is not present on the response. Is there anything else that needs done to get this to work?
|
126

If you are using IIS 7+, you can place a web.config file into the root of the folder with this in the system.webServer section:

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

See: http://msdn.microsoft.com/en-us/library/ms178685.aspx And: http://enable-cors.org/#how-iis7

answered Jul 15, 2012 at 17:08

7 Comments

I can't remember why anymore, but this method does not always work in IIS 7+
Hmm. The only reason I can think it wouldn't work is if a request originates from a non-CORS browser. But I'll continue to investigate.
Also, this would make the entire website CORS-friendly. If somebody wants to mark only a single action or controller as CORS-friendly, then the accepted answer is much better.
If you see the ASP.Net section, it has a hint: "Note: this approach is compatible with IIS6, IIS7 Classic Mode, and IIS7 Integrated Mode."
I am facing a cross- domain issue when I publish my app on the SharePoint environment. When I run my app on local environment my app runs fine, but when I publish it on azure to my sharepoint site it redirects to error page on Ajax.Begin form call. I tried this solution but it doesn't work for me. Is there any other alternative to it?
|
25

I ran into a problem where the browser refused to serve up content that it had retrieved when the request passed in cookies (e.g., the xhr had its withCredentials=true), and the site had Access-Control-Allow-Origin set to *. (The error in Chrome was, "Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true.")

Building on the answer from @jgauffin, I created this, which is basically a way of working around that particular browser security check, so caveat emptor.

public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
{
 public override void OnActionExecuting(ActionExecutingContext filterContext)
 {
 // We'd normally just use "*" for the allow-origin header, 
 // but Chrome (and perhaps others) won't allow you to use authentication if
 // the header is set to "*".
 // TODO: Check elsewhere to see if the origin is actually on the list of trusted domains.
 var ctx = filterContext.RequestContext.HttpContext;
 var origin = ctx.Request.Headers["Origin"];
 var allowOrigin = !string.IsNullOrWhiteSpace(origin) ? origin : "*";
 ctx.Response.AddHeader("Access-Control-Allow-Origin", allowOrigin);
 ctx.Response.AddHeader("Access-Control-Allow-Headers", "*");
 ctx.Response.AddHeader("Access-Control-Allow-Credentials", "true");
 base.OnActionExecuting(filterContext);
 }
}
answered Sep 7, 2013 at 8:30

1 Comment

I tried this method but gives me error: Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed
23

This is really simple , just add this in web.config

<system.webServer>
 <httpProtocol>
 <customHeaders>
 <add name="Access-Control-Allow-Origin" value="http://localhost" />
 <add name="Access-Control-Allow-Headers" value="X-AspNet-Version,X-Powered-By,Date,Server,Accept,Accept-Encoding,Accept-Language,Cache-Control,Connection,Content-Length,Content-Type,Host,Origin,Pragma,Referer,User-Agent" />
 <add name="Access-Control-Allow-Methods" value="GET, PUT, POST, DELETE, OPTIONS" />
 <add name="Access-Control-Max-Age" value="1000" />
 </customHeaders>
 </httpProtocol>
</system.webServer>

In Origin put all domains that have access to your web server, in headers put all possible headers that any ajax http request can use, in methods put all methods that you allow on your server

regards :)

answered Dec 11, 2015 at 9:54

2 Comments

Adding "Authorization" in Access-Control-Allow-Headers can also be useful if you intend to use Authorized queries.
Great answer! Just remind to include localhost port number to make it work under IIS Express
10

Sometimes OPTIONS verb as well causes problems

Simply: Update your web.config with the following

<system.webServer>
 <httpProtocol>
 <customHeaders>
 <add name="Access-Control-Allow-Origin" value="*" />
 <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
 </customHeaders>
 </httpProtocol>
</system.webServer>

And update the webservice/controller headers with httpGet and httpOptions

// GET api/Master/Sync/?version=12121
 [HttpGet][HttpOptions]
 public dynamic Sync(string version) 
 {
soniiic
2,6852 gold badges26 silver badges40 bronze badges
answered Sep 11, 2013 at 7:16

2 Comments

BTW, in sitefinity you need to add * to the System advanced settings in the security section
which are the files in which I need to update the controller headers?
9

WebAPI 2 now has a package for CORS which can be installed using : Install-Package Microsoft.AspNet.WebApi.Cors -pre -project WebServic

Once this is installed, follow this for the code :http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api

answered Apr 12, 2014 at 13:33

Comments

5

Add this line to your method, If you are using a API.

HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*"); 
answered Mar 14, 2014 at 11:10

Comments

5

This tutorial is very useful. To give a quick summary:

  1. Use the CORS package available on Nuget: Install-Package Microsoft.AspNet.WebApi.Cors

  2. In your WebApiConfig.cs file, add config.EnableCors() to the Register() method.

  3. Add an attribute to the controllers you need to handle cors:

[EnableCors(origins: "<origin address in here>", headers: "*", methods: "*")]

answered Dec 11, 2015 at 10:47

1 Comment

I had to use this method because I needed to set a custom header in my request, and the custom attribute method did not work with the browsers pre-flight request. This seems to work in all cases.
5

After struggling for a whole evening I finally got this to work. After some debugging I found the problem I was walking into was that my client was sending a so called preflight Options request to check if the application was allowed to send a post request with the origin, methods and headers provided. I didn't want to use Owin or an APIController, so I started digging and came up with the following solution with just an ActionFilterAttribute. Especially the "Access-Control-Allow-Headers" part is very important, as the headers mentioned there do have to match the headers your request will send.

using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MyNamespace
{
 public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
 {
 public override void OnActionExecuting(ActionExecutingContext filterContext)
 {
 HttpRequest request = HttpContext.Current.Request;
 HttpResponse response = HttpContext.Current.Response;
 // check for preflight request
 if (request.Headers.AllKeys.Contains("Origin") && request.HttpMethod == "OPTIONS")
 {
 response.AppendHeader("Access-Control-Allow-Origin", "*");
 response.AppendHeader("Access-Control-Allow-Credentials", "true");
 response.AppendHeader("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE");
 response.AppendHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, X-RequestDigest, Cache-Control, Content-Type, Accept, Access-Control-Allow-Origin, Session, odata-version");
 response.End();
 }
 else
 {
 HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
 HttpContext.Current.Response.Cache.SetNoStore();
 response.AppendHeader("Access-Control-Allow-Origin", "*");
 response.AppendHeader("Access-Control-Allow-Credentials", "true");
 if (request.HttpMethod == "POST")
 {
 response.AppendHeader("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE");
 response.AppendHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, X-RequestDigest, Cache-Control, Content-Type, Accept, Access-Control-Allow-Origin, Session, odata-version");
 }
 base.OnActionExecuting(filterContext);
 }
 }
 }
}

Finally, my MVC action method looks like this. Important here is to also mention the Options HttpVerbs, because otherwise the preflight request will fail.

[AcceptVerbs(HttpVerbs.Post | HttpVerbs.Options)]
[AllowCrossSiteJson]
public async Task<ActionResult> Create(MyModel model)
{
 return Json(await DoSomething(model));
}
answered Oct 9, 2019 at 22:32

Comments

4
 public ActionResult ActionName(string ReqParam1, string ReqParam2, string ReqParam3, string ReqParam4)
 {
 this.ControllerContext.HttpContext.Response.Headers.Add("Access-Control-Allow-Origin","*");
 /*
 --Your code goes here --
 */
 return Json(new { ReturnData= "Data to be returned", Success=true }, JsonRequestBehavior.AllowGet);
 }
answered May 4, 2015 at 11:46

Comments

2

There are different ways we can pass the Access-Control-Expose-Headers.

  • As jgauffin has explained we can create a new attribute.
  • As LaundroMatt has explained we can add in the web.config file.
  • Another way is we can add code as below in the webApiconfig.cs file.

    config.EnableCors(new EnableCorsAttribute("", headers: "", methods: "*",exposedHeaders: "TestHeaderToExpose") { SupportsCredentials = true });

Or we can add below code in the Global.Asax file.

protected void Application_BeginRequest()
 {
 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-Methods", "GET, POST, OPTIONS");
 HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "*");
 HttpContext.Current.Response.AddHeader("Access-Control-Allow-Credentials", "true");
 HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "http://localhost:4200");
 HttpContext.Current.Response.AddHeader("Access-Control-Expose-Headers", "TestHeaderToExpose");
 HttpContext.Current.Response.End();
 }
 }

I have written it for the options. Please modify the same as per your need.

Happy Coding !!

answered Oct 11, 2018 at 7:32

Comments

1

I'm using DotNet Core MVC and after fighting for a few hours with nuget packages, Startup.cs, attributes, and this place, I simply added this to the MVC action:

Response.Headers.Add("Access-Control-Allow-Origin", "*");

I realise this is pretty clunky, but it's all I needed, and nothing else wanted to add those headers. I hope this helps someone else!

answered Jun 24, 2020 at 6:07

Comments

0

In Web.config enter the following

<system.webServer>
<httpProtocol>
 <customHeaders>
 <clear /> 
 <add name="Access-Control-Allow-Credentials" value="true" />
 <add name="Access-Control-Allow-Origin" value="http://localhost:123456(etc)" />
 </customHeaders>
</httpProtocol>
answered Mar 27, 2018 at 9:17

Comments

0

If you use IIS, I'd suggest trying IIS CORS module.
It's easy to configure and works for all types of controllers.

Here is an example of configuration:

 <system.webServer>
 <cors enabled="true" failUnlistedOrigins="true">
 <add origin="*" />
 <add origin="https://*.microsoft.com"
 allowCredentials="true"
 maxAge="120"> 
 <allowHeaders allowAllRequestedHeaders="true">
 <add header="header1" />
 <add header="header2" />
 </allowHeaders>
 <allowMethods>
 <add method="DELETE" />
 </allowMethods>
 <exposeHeaders>
 <add header="header1" />
 <add header="header2" />
 </exposeHeaders>
 </add>
 <add origin="http://*" allowed="false" />
 </cors>
 </system.webServer>
answered Jan 29, 2019 at 16:13

Comments

0

To make the main answer work in MVC 5.

Use System.Web.Mvc instead of System.Web.Http.Filters.

using System;
using System.Web.Mvc;
// using System.Web.Http.Filters;
public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
{
 ...
}
answered Mar 5, 2021 at 14:33

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.