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 have an angular 2/4 application which makes request to a .Net Web Api 2.0 using Windows authentication. I can make GET and DELETE requests that work perfectly. However when I try to do POST or PUT request I am getting the following error:
PUT
The requested resource does not support http method 'PUT
POST
The request entity's media type 'text/plain' is not supported for this resource. No MediaTypeFormatter is available to read an object of type from content with media type 'text/plain
I know windows authenticaion is working because I can make GET and DELETE Reqeusts. I have the Content-Type header set to application/json and I have handled cors and preflight with the following in my Application_BeginRequest method
var referrer = Request.UrlReferrer.GetLeftPart(UriPartial.Authority);
if (Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.Headers.Remove("Access-Control-Allow-Origin");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", referrer);
HttpContext.Current.Response.StatusCode = 200;
HttpContext.Current.Response.End();
}
if (Request.Headers.AllKeys.Contains("Origin"))
{
HttpContext.Current.Response.Headers.Remove("Access-Control-Allow-Origin");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", referrer);
}
I have also included the following in my web.config
Cors
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Credentials" value="true" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS" />
<add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept, X-Pagination, Authorization" />
<add name="Access-Control-Expose-Headers" value="X-Pagination" />
</customHeaders>
</httpProtocol>
<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>
Windows Authentication
<authentication mode="Windows" />
<authorization>
<deny users="?" />
</authorization>
Any idea what could cause GET and DELETE to work but not POST, PUT, PATCH?
Update - Controller Methods
[Route("")]
[HttpPut]
public IHttpActionResult Put([FromBody] Header updatedEntity)
{
if (updatedEntity == null)
return BadRequest();
var entity = UnitOfWork.Headers.Get(updatedEntity.Id);
if (entity == null)
return NotFound();
// Setup up entity
UnitOfWork.Commit();
return StatusCode(HttpStatusCode.NoContent);
}
[HttpGet]
[Route("", Name = "RouteName")]
public IHttpActionResult List([FromUri] HeaderResourceParameters parameters)
{
parameters = parameters ?? new HeaderResourceParameters();
var recipients = UnitOfWork.Recipients.GetAll().ToList();
var entities = UnitOfWork.Headers.List(parameters)
.Select(o => new HeaderViewModel
{
// Entity Setup
});
if (entities == null)
return NotFound();
return Ok(entities);
}
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.
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>
I just experienced this same issue, trying to enable CORS globally. However I found out it does work, however only when the request contains a Origin header value. If you omit the origin header value, the response will not contain a Access-Control-Allow-Origin.
I used a chrome plugin called DHC to test my GET request. It allowed me to add the Origin header easily.
None of these answers really work. As others noted the Cors package will only use the Access-Control-Allow-Origin header if the request had an Origin header. But you can't generally just add an Origin header to the request because browsers may try to regulate that too.
If you want a quick and dirty way to allow cross site requests to a web api, it's really a lot easier to just write a custom filter attribute:
public class AllowCors : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (actionExecutedContext == null)
{
throw new ArgumentNullException("actionExecutedContext");
}
else
{
actionExecutedContext.Response.Headers.Remove("Access-Control-Allow-Origin");
actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
}
base.OnActionExecuted(actionExecutedContext);
}
}
Then just use it on your Controller action:
[AllowCors]
public IHttpActionResult Get()
{
return Ok("value");
}
I won't vouch for the security of this in general, but it's probably a lot safer than setting the headers in the web.config since this way you can apply them only as specifically as you need them.
And of course it is simple to modify the above to allow only certain origins, methods etc.
No-one of safe solution work for me so to be safer than Neeraj and easier than Matthew just add:
System.Web.HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
In your controller's method. That work for me.
public IHttpActionResult Get()
{
System.Web.HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
return Ok("value");
}
I found this question because I was having issues with the OPTIONS request most browsers send. My app was routing the OPTIONS requests and using my IoC to construct lots of objects and some were throwing exceptions on this odd request type for various reasons.
Basically put in an ignore route for all OPTIONS requests if they are causing you problems:
var constraints = new { httpMethod = new HttpMethodConstraint(HttpMethod.Options) };
config.Routes.IgnoreRoute("OPTIONS", "{*pathInfo}", constraints);
More info: Stop Web API processing OPTIONS requests
Hope this helps someone in the future. My problem was that I was following the same tutorial as the OP to enable global CORS. However, I also set an Action specific CORS rule in my AccountController.cs file:
[EnableCors(origins: "", headers: "*", methods: "*")]
and was getting errors about the origin cannot be null or empty string. BUT the error was happening in the Global.asax.cs file of all places. Solution is to change it to:
[EnableCors(origins: "*", headers: "*", methods: "*")]
notice the * in the origins? Missing that was what was causing the error in the Global.asax.cs file.
Hope this helps someone.
WEBAPI2:SOLUTION.
global.asax.cs:
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
IN solution explorer, right-click api-project. In
properties window set 'Anonymous Authentication' to Enabled !!!
Hope this helps someone in the future.
I am a beginner in WCF, I have been attempting to enable CORS for a WCF service hosted in my IIS. I have gone through several posts and Stack Overflow questions, and all answers are leading me to different solutions and none of them works.
Can someone explain me how to achive this? I tried creating a global.asax and adding begin_request event to set up the headers, but it changed nothing.
This is what I used:
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");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}
Where should I start for this and which is the best way for achieving this?
I assume WCF service is up and running.Fix in Web.config .Add below section in system.webServer section.
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*"/>
<add name="Access-Control-Allow-Headers" value="Content-Type, Accept" />
<add name="Access-Control-Allow-Methods" value="POST,GET,OPTIONS" />
<add name="Access-Control-Max-Age" value="1728000" />
</customHeaders>
</httpProtocol>
Caution
NOTE! The Access-Control-Allow-Origin setting is set to a value of "*". This will allow all callers to have access. You can specify only your caller.
From your existing implementation it should work.However I have slightly tweaked the code and it works for me.
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" , "GET, POST" );
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Authorization, Origin, Content-Type, Accept, X-Requested-With");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000" );
HttpContext.Current.Response.End();
}
}