I have this App where I would like to set my custom headers in the Web.Config, alas this is not always fool proof.
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="*" />
<add name="Access-Control-Allow-Headers" value="*" />
</customHeaders>
The above set and iterations of it such as
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="OPTIONS,GET,PUT,DELETE,POST" />
<add name="Access-Control-Allow-Headers" value="Authorization,Content-Type" />
</customHeaders>
has not worked worked for me in all scenario's. As of now this setting works in about 50% of the test machines and gives 405 Method Not Allowed in others.
The alternative is set this in WebApiConfig.cs and uncomment the custom headers in Web.config.
//Web API Cross origin requests - Enable
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
Why is there so much ambiguity in this and how do I know for sure where CORS will work all the time? I am really interested in setting CORS on Web.config only as I would like the flexibility of modifying it in the deployed version.
I believe that your 'random' issue occurs because you are not handling the preflight Options requests for PUT and Delete verbs.
For the two verbs mentioned above an extra request is generated, Options, to which Web API needs to respond in order to confirm that it is indeed configured to support CORS.
To handle this, all you need to do is send an empty response back. You can do this inside your actions, or you can do it globally like this:
protected void Application_BeginRequest()
{
if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
{
Response.Flush();
}
}
This extra check was added to ensure that old APIs that were designed to accept only GET and POST requests will not be exploited. Imagine sending a DELETE request to an API designed when this verb didn't exist. The outcome is unpredictable and the results might be dangerous.
Also, in web.config, you should specify the methods instead of using *
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
There is no ambiguity with CORS, you have a few cases that you need to think about
1- if you want to enable CORS for your Web APIs only use "Microsoft.AspNet.WebApi.Cors" library.
2- if you want to enable CORS for the whole website (including the Web APIs, SignalR, ..etc ) use "Microsoft.Owin.Cors" library.
using any library from the above 2 will definitely work and cors will be enabled, now if you want to configure the urls, you can do that from your database/config file, so when your application starts the url that you pass to the EnableCors for example can come from the database/config file, but the bottom line is to avoid adding any cors headers to the web.config.
To know to enable CORS for your Web API, you can have a look to my article here, which enables CORS for the Web APIs and use it from AngularJS client.
Hope that helps.
For anyone reading this, this may help.
Even with the following startup code
var cors = new EnableCorsAttribute("*", "*", "GET, POST, PUT, DELETE, OPTIONS");
config.EnableCors(cors);
I had to explcitly add the verbs to the Web Api action method:
[Route("sanity")]
[HttpOptions]
[HttpPost]
public List<PostImportView> Sanity(SanityFilter filter)
{
....
Pretty pointless and annoying
Related
I have an Angular page which is making use of an Entity Framework powered ASP.NET server. Both Angular and ASP.NET applications run on different local addresses. To prevent CORS errors, I have configured some settings at the server side.
At the ASP.NET side, in WebApiConfig.cs I have enabled all of the access permissions from the Angular local address with this;
config.EnableCors(new EnableCorsAttribute("http://localhost:4200", headers: "*", methods: "*"));
However, when I trying to Edit a value from the Angular page, I am still having the CORS error.
Access to XMLHttpRequest at 'http://localhost:62677/Assets/Edit/177738ba-16cd-4b08-b339-974f0547e626' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
Inserting a new value to the database or getting all of the values from the database is working without the CORS error but editing an existing value gives an error.
I tried to add a break-point at the above code in WebApiConfig.cs and debug it, however, line of code is never reached.
Any help is appreciated, thanks
Addition: Also I have the following configurations in my Web.config file;
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
New ERROR after implementing Shyam Vemula's solution:
Access to XMLHttpRequest at 'http://localhost:62677/Assets/Edit/177738ba-16cd-4b08-b339-974f0547e626' from origin 'http://localhost:4200' has been blocked by CORS policy: Method PUT is not allowed by Access-Control-Allow-Methods in preflight response.
Try this one. Add the following in Global.asmx
void Application_BeginRequest(object sender, EventArgs e)
{
var context = HttpContext.Current;
var response = context.Response;
// enable CORS
response.AddHeader("Access-Control-Allow-Origin", "*");
if (context.Request.HttpMethod == "OPTIONS")
{
response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS");
response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
response.End();
}
}
and Remove this from Web.config file
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
I am running a WEB API project locally through Visual studio, on port 49374.
I am then running an MVC project locally through VS, on port 57062.
I am trying to call an API in my WEB API project (49374), from the MVC project(57062), but am getting a 401.2 response, see below:
When I call the API directly from the browser, it works fine.
CORS is setup in the Web API Web config as follows:
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http://localhost:57062" />
<add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS, PUT, DELETE" />
<add name="Access-Control-Allow-Headers" value="Content-Type, Accept" />
<add name="Access-Control-Allow-Credentials" value="true" />
<!--<add name="Access-Control-Allow-Credential-Header" value="true"/>-->
</customHeaders>
</httpProtocol>
and the project has the following settings on VS:
I am out of ideas as to what the problem could be - can anyone suggest anything?
I have encountered the same probleme. IIS Express does not seem to use the custom headers in the web.config.
I fixed it by adding in the global.asax.cs :
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (Context.Request.Headers.AllKeys.Contains("Origin"))
{
Context.Response.AddHeader("Access-Control-Allow-Origin", "http://localhost:57062");
Context.Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
Context.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
Context.Response.AddHeader("Access-Control-Allow-Credentials", "true");
if (Context.Request.HttpMethod == "OPTIONS") Context.Response.End();
}
}
I am trying to get CORS to work with a new WebAPI project. The project is just the default WebAPI template (i.e. has MVC and WebAPI references) using ActiveDirectoryBearerAuthentication.
Whenever I try and make a request to my API I am met with the following error:
XMLHttpRequest cannot load https://localhost:44385/api/values. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://localhost:44369' is therefore not allowed access.
I have installed Microsoft.Owin.Cors, and Microsoft.AspNet.WebApi.Cors.
My WebApiConfig is this:
public static void Register(HttpConfiguration config)
{
config.EnableCors();
....
My Startup.Auth is this:
public void ConfigureAuth(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
....
Solutions around the net say to add:
<customHeaders>
<!-- Adding the following custom HttpHeader will help prevent CORS from stopping the Request-->
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
to the web.config. However, doing this just allows everything regardless of whether Microsoft.AspNet.WebApi.Cors is installed, enabled, or not.
To allow only a single domain you can do the following:
<system.webServer>
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
<clear />
<add name="Access-Control-Allow-Origin" value="http://www.myalloweddomain.com" />
</customHeaders>
</httpProtocol>
</system.webServer>
However, that's only allowed for a single domain. If you try to add an additional add node your site won't load. If you want to allow multiple domains, then you need to try one of the solutions listed here.
Things to check:
Owin kicks in on IIS (make sure you're including Microsoft.Owin.Host.SystemWeb)
Check that IIS doesn't hijack your request IIS hijacks CORS Preflight OPTIONS request
Use fiddler to fire OPTION request directly to specified url (sometimes the PREFLIGHT request just mask 500 returned by server) - browsers aren't very good in handling that
Put:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="GET, PUT, POST, DELETE, HEAD, OPTIONS" />
<add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
</customHeaders>
</httpProtocol>
in the Web Config, this literally covers everything and will let through everything according to the "*" wildcard. If you want concrete domains to be whitelisted you put them into:
<add name="Access-Control-Allow-Origin" value="*" />
Enabling you can do either through global configuration as you have been doing or instead with an attribute:
[EnableCors(origins: "*", headers: "*", methods: "*")]
On the relevant controller. Its one of the two, if you use both options it will choke.
Also you can write your own attribute which can handle loading of origins, headers and methods from a web.config appSettings or from a database by overriding EnableCors attribute if you prefer but that is already beyond the scope of your question I think.
I'm getting the following error:
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource.
when making the following request to my web api from my angular2 app:
return this.http.get("http://localhost/api/test", { headers })
.map(res => this.extractData(res))
.catch(this.handleError);
Some considerations:
I'm using Microsoft.Owin.Cors
Requests work fine when they don't include headers. This one includes headers for authentication purposes.
I can make the request using Chrome.
Microsoft.Owin.Cors is installed in the solution
app.UseCors(CorsOptions.AllowAll); is at the start of the configuration method of startup.cs
The following is included in the web.config file:
<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,runtimeVersionControllerv4.0" />
</handlers>
thanks!
I think the problem is that you don't configure preflight requests on the server side (for OPTIONS methods).
There are two kinds of requests with CORS:
Simple requests. This use case applies if we use HTTP GET, HEAD and POST methods. In the case of POST methods, only content types with the following values are supported: text/plain, application/x-www-form-urlencoded and multipart/form-data.
Preflighted requests. When the ‘simple requests’ use case doesn’t apply, a first request (with the HTTP OPTIONS method) is made to check what can be done in the context of cross-domain requests.
When adding headers, you switch from simple to preflight requests. So an OPTIONS request is executed under the hood before the target request.
See this article for more details:
http://restlet.com/blog/2015/12/15/understanding-and-using-cors/
add these lines to webapiconfig.cs file
var cors = new EnableCorsAttribute("", "", "*");
config.EnableCors(cors);
you can do one more thing in ApplicationOAuthProvider.cs add this line in GrantResourceOwnerCredentials method
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
Good Morning All,
I am trying a very basic form.submit and for some reason it ALWAYS comes back as failure.
Also using a local webservice in .NET.
I must be missing something very basic... or maybe something with the way the data is coming back.
I have attached few pictures to show how I am attempting:
image1 - form.submit
image2 - service.cs
image3 - how I am returning result from .NET webservice locally
Apologies for the images... for some reason cutting and pasting code is not working.
Thank you!
Stephen
here is a picture of debugger in webservice
first row is var variable
second row (x2) is converted to json using JsonConvert.SerializeObject
lastly is a pictures of debugger from browser upon return
I also have been trying to understand CORS... so I added the following to my web.config which doesn't help
<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" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
</system.webServer>
enter code here
here is firefox debugger
I adjusted my web.config to allow options and still get error
STATUS CODE 405 METHOD NOT ALLOWED
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*"/>
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="OPTIONS, TRACE, GET, HEAD, POST, PUT" />
<!--<add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />-->
</customHeaders>
</httpProtocol>
</system.webServer>
OKAY... I made some changes... I removed those lines from my web.config and added a Global.asax.cs page with the following:
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("Cache-Control", "no-cache");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization, X-Requested-With");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}
Now it seems to go through successfully, but still hits failure. Am I on to something here? Is it my json format?
result
Your response has backslashes, which is not valid JSON. It has to be {"success":true} without backslashes.
This should be due to double serialization. Where you debugged it, it's OK. But you should be serializing it one more time somewhere else. Make sure you avoid double serialization.