If you have done any extensive work with AJAX calls, then the odds are that you have fun into an unfriendly (only for security purposes) mechanism that will have your request ground to a halt and its name is CORS (Cross Origin Resource Sharing). Most commonly, this will occur when you are attempting to pull data from a source other than where the request originated from (which raises flags in the security department) although the requests may often be legitimate.
This article will discuss the steps necessary to implement and enhance CORS support within ASP.NET WebAPI allowing you to handle CORS Requests at a Global, Controller, or Action level to provide more flexibility when working with possible cross-origin requests.
A Course on CORS
Cross Origin Resource Sharing (CORS) as previously mentioned is a security mechanism that allows web pages, sites and applications to make AJAX calls and HttpRequest
s to other domains.
These cross-domain requests are forbidden within browsers that lack CORS due to famous same-origin policy for web requests (which basically states that scripts should only be permitted to run from the domain they originated from) which could lead to nasty things like XSS attacks that translate into you (and your users) having a bad day.
An example CORS request can easily be created by using something like a very basic AJAX call to attempt to access today’s Google doodle:
<script type='text/javascript'>
$(function(){
$.ajax({ url: "http://www.google.com", success: function(data){
alert(data);
}});
});
</script>
and if you check out the console area of your browser – you’ll see something that looks a bit like this:
Too Legit To Quit
CORS requests can actually have legitimate purposes aside from scraping screens and data from other domains too. Consider the following situation where you have two sites being hosted:
As you can see above, groundcontrol.com features a WebAPI that you may want to attempt to consume services from using majortom.com. However, due to the way that CORS works, it will recognize these two sites as coming from different origins as they have different hosts (ports and protocols can also constitute different origins) and it will block these requests even though you own both of these domains for security reasons (it doesn’t really care that you own them).
Fear not. Not all requests of this type are illegitimate and CORS features the necessary tools and protocols for handling legit cross-domain and cross-origin requests.
Ground Control to Major Tom
To demonstrate this functionality, we can create a very basic harness to make an AJAX Request that would be considered cross-domain between these two applications. Firstly, we will go into the Web API project (Ground Control) and create a very simple action to send out to our soon to be lonely astronaut.
Within the ValuesController
of the WebAPI
Project, create the following action:
public class ValuesController : ApiController
{
public string Get()
{
return "Can you hear me Major Tom?";
}
}
In order to test that this is working properly, we will also create a view that will perform an AJAX call to this project and retrieve our message:
<head runat="server">
<meta name="viewport" content="width=device-width" />
<title>Ground Control</title>
<script src="@Url.Content("~/Scripts/jquery-1.8.2.js")"></script>
<script type="text/javascript">
$(function () {
$.ajax({
url: "http://localhost:1337/api/values",
type: "GET",
success: function (data) {
alert(data);
},
error: function (event) {
alert("Transmission Failed. (An error has occurred)");
}
});
});
</script>
</head>
Notice that we have explicitly defined this as running on port 1337, which can easily be set through the Properties of your Application (for demonstration purposes):
For this example, we will want to ensure that our Web API service is running at a specific port (so it can be more easily targeted) and then when we navigate to the Home Controller’s Index View, we will be presented with our AJAX Request from the WebAPI call:
Stepping through the Door
Now it doesn’t do much good to have our Ground Control communicating with themselves, so let's try sending these transmissions to our acclaimed astronaut Major Tom who is deep in the depths of space where there is no doubt all types of CORS-related interference to mess with our transmission.
To do this, we will create a very basic MVC Controller within the same solution to function as our Major Tom (it will be a very basic Empty MVC4 Project). Within this project, we will take the following steps:
- Create a
HomeController
(eerily similar to the one within the WebAPI Project) - Create a View for the Index Action of the Home Control (again so very similar to the WebAPI project)
- Copy the exact contents of the Index View from the WebAPI Project into the corresponding MVC View
After performing these steps, we are going to attempt to run our MVC Project to see if we can make contact with Ground Control:
The Request from Ground Control to Major Tom failed (further inspection will reveal CORS prevented it)
Although this application was targeting the proper URL and port of our WebAPI project, the transmission did not go through successfully. Using the Developer Tools (F12) within your favorite browser, you can check out the Console to see exactly what the cause of the error was:
As you can see by the Access-Control-Allow-Origin error, CORS blocked the access attempt.
As you might have expected, CORS determined that the request that was being made within the AJAX call was a cross-browser / cross-domain request and it quickly denied it. So it appears that Ground Control will actually need to determine a method to get this message out to Major Tom (our MVC Project) in time.
Technical Difficulties with Ground Control
This issue can be resolved by making the following change within the web.config file of our WebAPI:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
</system.webServer>
Adding the Access-Control-Allow-Origin header with a value set to an asterisk (wildcard) will allow any origin to make requests to the Web API. So after making these changes within our WebAPI
Project, we can again try running the MVC Application to see if it can now properly receive the transmission being sent from Ground Control:
Major Tom (MVC) successfully receives a CORS Response from Ground Control (WebAPI)
So with the minor addition of the Access-Control-Allow-Origin header, we can successfully make CORS requests in between different applications using Web API. If you want to test this out or expand upon the functionality in this example, you can download it below:
Stay tuned for more from Major Tom.
This post reviewed over a very basic method of enabling CORS Requests to be made using ASP.NET Web API, however simply modifying an HTTP Header manually is not the only method for handling this. In a following post, I’ll elaborate a bit more on some of the other methods that can be used to handle CORS Requests as well as some of Microsoft’s planned changes to allow for CORS functionality to be integrated into Web API Projects.
Filed under: CodeProject, Development