Web API as we know is a way to build Services over HTTP. Building services over HTTP makes them available to a wider audience of clients that only need an HTTP implementation, as opposed to say SOAP services.
However, there is one caveat being AJAX request to HTTP services can be made only from URLs of the same Origin. For example if your web services are hosted on http://myservices:8080/api/ then the browser will allow applications hosted on http://myservices:8080/ to make AJAX calls to these services. But services/web applications hosted on http://myservices:8081/ or any other port for that matter, cannot access the HTTP resource/api over AJAX. This limitation is a default browser behavior for security considerations.
However, W3C has a CORS spec that outlines the ‘rules and regulations’ to enable Cross Origin Resource Sharing aka CORS. ASP.NET MVP Brock Allen built out CORS support for Thinktecture, which was later pulled into ASP.NET Web API core and is now available in pre-release version of Web API 2.0. Even though Web API 2.0 is going to be a part of Visual Studio 2013, you can try it out today in Visual Studio 2012 with .NET Framework 4.5.
Web API 2.0 and ASP.NET MVC have moved on to .NET Framework 4.5, so as a result you cannot try this out unless your project is targeted for 4.5.
So without further delay, let’s jump right in and see how to enable and use Cross Origin Resource Sharing in Web API 2.0.
Setting up the Web API Sample
Now setting up a Sample would have been very easy had we used Visual Studio 2013. It’s practically available out of the box. However, thanks to Nuget package based release of the Web API components, we can very well do it in VS 2012 too.
Getting Started with an Empty Project
Instead of starting with the usual Web API project that will use the stable release of Web API, we start off with an ASP.NET Project and use the Empty project template. This will give us minimum cruft with respect to dependencies.


Once the project is ready, right click on the Solution Explorer and go to Manage Nuget packages. Here we set the package types to – ‘Include Prerelease’ and then do a search for ‘Web API’. As shown below, we’ll get a set of search results from which we pick ‘Microsoft ASP.NET Web API’. Note, its version is 5.0.0 (beta2).
Once we click install, Nuget Package Manager will do its thing to download the required dependencies. We’ll end up with a license dialog like the following, giving you an idea of the sub-dependencies getting installed:
Next we install the CORS package as follows:
Once these are installed, we have Web API setup and good to go.
Setting up Web API Help Pages and Test Client
Yao Huang Lin from the ASP.NET team built a very useful “Web API Help Pages” package that dynamically generates API documentation for your Web API services. However, he didn’t stop at that; he also built a test client framework that provides a dynamic client to post data to your services. These two packages are a must-have when doing Web API development.
Since we want the latest and greatest version (pre-release), we have one manual step to take before we can install these two packages. From the Package Manager Console, fire the following command
PM> uninstall-package Microsoft.AspNet.Mvc.FixedDisplayModes
We had to uninstall the FixedDisplayModes package because the Web API Test Client package updates MVC to MVC 5 beta and for reasons I have not investigated further, FixedDisplayModes still doesn’t have a version compliant with MVC 5 beta.
Next we go to the Nuget Package Manager again and install Web API Help Pages.
Note, if you search for ‘Web Api’, the Help Pages package is in the second page of the search results.
As the Web Pages get installed, you’ll see the following license agreement screen, which essentially hints at MVC and Razor engines getting updated.

Finally, search for “Test Client for Web API” in the Package Manager and install the Test Client
This has an additional dependency of jQuery, jQuery UI and KnockoutJs. You can install these from the Package Manager Console as follows
PM> install-package jquery
PM> install-package jquery.ui.combined
PM> install-package KnockoutJs
Configuring the Test Client
The test client requires two lines of configuration. Open the Api.cshtml in the following path \Areas\HelpPage\Views\Help\. Add the following at the bottom of the page (after the last </div> tag).
@Html.DisplayForModel("TestClientDialogs")
Inside the Scripts section add the following line
@Html.DisplayForModel("TestClientReferences")
With this the test client is good to go.
Creating an Entity and Building a CRUD service for it
In the Models folder, add a new class called BlogPost as follows:
public class BlogPost
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public string Author { get; set; }
}
Next we build the application.
On the Controller’s folder, right click and select Add Controller to add a Web API Controller using EntityFramework for data persistence.

Setup the controller as above and click Add to scaffold the Api Controller. We are at a point where we could save this project template so that we can create a new Web API 2.0 project in one shot.
Saving the project template
To save the Project Template, click on File > Export as Template menu. We’ll get a Wizard as follows

Click Next and Provide a name and description
Creating a second Solution
To test out CORS, we need two web applications calling each other. To keep things simple, we’ll simply use the newly created template in a new Solution and create a new Project

Click OK and we are done. We have two projects with same code if we were to post from one project to another, it would be Cross Origin.
To avoid port conflicts, go to one of the Project’s property panel and change the Port of execution (the port gets saved as a part of the Template and is thus same). Here I’ve changed port of WebApiCors2 to 54733.

Update the Web.Config’s connection string name to WebApiCorsContext2 and update the Context class as well to use the new connection string
public WebApiCorsContext()
: base("name=WebApiCorsContext2")
{
}
Testing and Enabling CORS
Before we see how to enable CORS, let’s run our solutions, we use Firefox as the browser for WebApiCors project and IE as the browser for the WebApiCors2 project. In both, navigate to the /Help page. We’ll see the same APIs are available on both applications.

Let’s do a POST from WebApiCors to the app @ Port 54732 (same domain). To do the post, click on the POST link in the Home Page. This will bring up a Page with sample data and a ‘Test API’ button at bottom right hand corner. Clicking on the Button will bring up a dialog with sample data that needs to be posted.
We update the sample data slightly and hit Send. The response we get is as follows

As we can see, this is a RESTful response with the Body containing the new Entity, and the Location header containing the URL where the newly created Entity can be found. So we were able to post to same domain.
Now if we take the same Input dialog, and try to send it to the application on port 54733 as follows

We’ll get the following response. It’s not a very elegant response but essentially it’s a failure of a cross domain call.

Enabling CORS in WebApiCors2 (Port No: 54733)
Let’s keep the WebApiCors project running and stop the WebApiCors2 project. In the App_Start\WebApiConfig.cs we’ll enable CORS as follows
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
The three constructor arguments are
- Origins: Which sources should we accept request from. * = every site on the internet
- Headers: Which headers should be accepted. *=anything is fine.
- Methods: Which HTTP Verbs should be accepted. * = all verbs
So the above configuration sets up the API as completely public and accessible to all Origins. To test, we run WebApiCors2 project and post the same data again from WebApiCors. This time we get a success message as follows
To confirm that this is indeed the same data, in IE, where we have WebApiCors2 site running, we navigate to the Help Page and do a get request. As we can see here, the data returned is the same that was posted across domains.
With that we have seen how to setup Web API Help Pages, Test Client, CORS and Enable CORS. We enabled blanket permissions for CORS in our example. Next we look at some of the options that the CORS library provides and see how we can fine tune CORS access to Web API resources.
CORS Options
In the above sample, we saw how we could enable CORS using an instance of EnableCorsAttribute object. Now the name would have given you a hint that you can enable CORS via attributes as well.
That is actually a very correct assumption. If we were to enable CORS only via a central location, we could potentially end up with the same dissonance that we had with routing. To avoid that, CORS can be enabled at API level as well.
For example, let’s modify the WebApiCors2 project and remove the permissions from the WebApiConfig.cs. Next in the BlogPostsController we add the following attribute
[EnableCorsAttribute("https://www.dotnetcurry.com/", "*", "*")]
public class BlogPostsController : ApiController
{
…
}
The above attribute implies that requests from the domain www.dotnetcurry.com will be accepted. So if requests are sent from localhost or any other domain other than dotnetcurry, the request will fail.
Similarly we can filter by headers also. The following configuration says that the request must accompany a custom header called x-myheader. If this is missing, the request will be rejected.
[EnableCorsAttribute("*", "origin,x-myheader", "*")]
public class BlogPostsController : ApiController
{
…
}
Note that origin is the default as per the CORS spec. Without it, the request will be denied as well.
Finally we can filter by Http Verbs. For example, the following enables GET requests from any origin with any header
[EnableCorsAttribute("*", "*", "GET")]
public class BlogPostsController : ApiController
{
…
}
If one tried to do a POST across origins it would be rejected.
Customizing Policies
You can implement your own custom class and either apply it globally or implement it as an attribute and apply it at the class level. With that, we wrap up this introduction to CORS in Web API 2.0.
Conclusion
CORS policies are an important part of providing correct authorization levels to ASP.NET Web API services. Without CORS, we had to use hacks like JSONP which we no longer have to use when building Web API based services.
Caveat: Not sure if it’s a bug in IE10 but CORS requests were going though in IE10 on Windows 8 hence I used Firefox to show how CORS requests get blocks or passed on depending on the permissions.
Download the entire source code of this article (Github)
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Suprotim Agarwal, MCSD, MCAD, MCDBA, MCSE, is the founder of
DotNetCurry,
DNC Magazine for Developers,
SQLServerCurry and
DevCurry. He has also authored a couple of books
51 Recipes using jQuery with ASP.NET Controls and
The Absolutely Awesome jQuery CookBook.
Suprotim has received the prestigious Microsoft MVP award for Sixteen consecutive years. In a professional capacity, he is the CEO of A2Z Knowledge Visuals Pvt Ltd, a digital group that offers Digital Marketing and Branding services to businesses, both in a start-up and enterprise environment.
Get in touch with him on Twitter @suprotimagarwal or at LinkedIn