Friday, 14 August 2015

Cross-Origin Requests (CORS) in ASP.NET Web API 2

Hello frnds,

In my previous post CRUD with AngularJS and ASP.Net Web API, I tried to show you, how to perform CRUD using AngularJs and ASP.NET web API.
In this example we had a ASP.NET Web API called 'Book API' and AngularJs views which talks to book api. As part of this example our web api and angularjs view both were part of same application. It means application and APIs both are running under same domain and port.

Now imagine, if our Book APIs are hosted in other domain and we need to consume it through AngularJS or Javascript/jquery app deployed/running in different domain. Problem looks very simple but fact is that we can't perform cross-origin/domain communication. So how to tackle this cross origin calls then, and the answer is using CORS  in ASP.NET Web API 2.





What is CORS?
Cross Origin Resource Sharing (CORS) is a W3C standard that allows a server to relax the same-origin policy. Using CORS, a server can explicitly allow some cross-origin requests while rejecting others. CORS is safer and more flexible than earlier techniques such as JSONP.

What is "Same Origin"?
Two URLs have the same origin if they have identical schemes, hosts, and ports. (RFC 6454)
These two URLs have the same origin:
http://example.com/foo.html
http://example.com/bar.html

These URLs have different origins than the previous two:
http://example.net - Different domain
http://example.com:9000/foo.html - Different port
https://example.com/foo.html - Different scheme
http://www.example.com/foo.html - Different subdomain

For details please visit: Enabling Cross-Origin Requests in ASP.NET Web API 2.

Now let's do the example.
On first step what we will do is, deploy our Book API (which we have created as part of above mentioned post 'CRUD with AngularJS and ASP.Net Web API'. and then our target will be to consume BooKAPIs from another application hosted with different domain or port.
I deployed my BookAPI to IIS and URL for BooKAPI for me is: "http://localhost:80/AngularJSExample/api/BookAPI".

Next let's create a simple asp.net application. For simplicity, In this application I am going to have a simple html page called "Home.html" and in this I wrote jqury code to access the BookAPI url to display all the books. Here is the code for Home.html.
<head>
    <title>CORS Example</title>
</head>
<body>
    <script src="Scripts/jquery-2.1.4.min.js"></script>
    <button id="btnGetBooks">Get Books</button>
    <div id="bookDiv"></div>
    
    <script>
        $(function () {

            var getBookList = function () {
                $.get(url).success(displayBooks).fail(displayErrors);
            };

            var displayBooks = function (data) {
                for (i = 0; i < data.length;i++) {
                    $("#bookDiv").append('Id=' + data[i].Id + ' Name=' + data[i].Name + ' Author=' + data[i].Author + '<br/>');
                }
            }

            var displayErrors = function (data) {
                $("#bookDiv").append(JSON.stringify(data, null, 1));
            }

            var url = "http://localhost/AngularJSExample/api/BookAPI"

            $("#btnGetBooks").click(getBookList);
        });
    </script>
</body>
</html>

Here is the UI for above code:

In above html, we have a button and on click of this button application will fetch books detail from BookAPI running under http://localhost:80/AngularJSExample/api.

In Html, I have a div which will show the result. On click of button I am calling the BookAPI using jquery $.get() method. For jquery, either you install directly to your application using nuget packages and refer it Or you can directly refer it through online CDN links.




Now I run it and click on 'Get Books' button then this is what you will see in page as output.



It means BookAPI is not allowing cross-origin communication. For your attention though both the application running under same host but ports are different. BookAPI running under port 80 and Home.html application running under port 81 and that's why asp.net web api (bookapi) is refusing the connection requested by port 81.
Here ASP.NET Web API 2 introduced the feature of CORS which makes our life easier on cross-origin connections.

To enable CORS feature for our BookAPI we need to follow few steps. Let's do it.

Follow below mentioned steps to enable CORS for your web api.
1. Install "Microsoft ASP.NET Web API  CORS" package using nuget package manager to you web api application project(please refer below screenshot here)



2. Open WebApiConfig.cs add settings to enable Cors by registering it to work it globally for all api controllers. To do this add below line of code to your 'Register' method:
config.EnableCors(new EnableCorsAttribute("*", "*", "GET"));
Here
first parameter '*' says, allows any orgin,
second parameter '*' says, allows any header,
third parameter 'GET' says, allows only GET methods.

3. OR go to individual API controller and enable it at controller/action method level and add 'EnableCors' attribute to the controller/action method as defined here:
[EnableCors("*","*","GET")]

'EnableCors' attribute presents under 'System.Web.Http.Cors' dll. So you include this you controller as
using System.Web.Http.Cors;

4. Deploy/update your app to IIS.

Now run Home.html page which we created as separate application and click on 'Get Books' button. Here is the result which we get:

That's it.

Thank You for reading. Feel free to give your feedback/comment.