Cross Origin Request in Web API

In this post, I am going to show you how to call a Web API/RestulFul service from client side using AngularJS. It looks pretty simple. But what if your Web API is hosted on a different domain. Then if you try to make a call to Web API you will get an error, a cross domain error.

The idea is, if you are working on a distributed application or due to architectural decision, you want to host your web application on a different domain, and middle layer will be on a different domain and exposed as a RestFul service. This will be a good idea, if later you want to expose your RestFul service to a vendor it will be quite handy. Nowadays AngularJS framework is very popular in developing web applications.

Now I want to develop a web application where my website will be hosted on a different domain and on a separate server.  Whereas I want to exposed my middle layer as RestFul Services and these services will be hosted on a different domain and a server. From web application I want to call RestFul services through AngularJS.  But the problem arises is, if I try to make a AJAX call to a service hosted on a different domain browser security will prevent this call. This restriction is called the same-origin policy, and prevents a malicious site from reading sensitive data from another site.

W3C comes up with a standard to deal with this issue. CORS (Cross Origin Resource Sharing) standard allows a server to explicitly allow cross origin request while rejecting other. CORS is a safe way to as compared to JSONP for cross origin request.

Lets start with our example. I will use Visual Studio 2013, WebAPI 2 and AngularJS to explain how to use CORS.

Lets start a new web project in Visual Studio 2013 and name is CROS. To make the example simple, I will select an empty web site template and check the WebAPI checkbox.

cros-img1

cros-img2

Next add a new Web APi empty controller in your project, under the Controller folder. Name the controller as ServiceAPI. And add these following line of code. I want to make the example simple, our Get method will return a string.

namespace CORS.Controllers
{
    public class ServiceAPIController : ApiController
    {
        public string Get()
        {
            return "This is a messsage from Service API";
        }
    }
}

Now compile the project and start the project, and when you type the following URL in your browser you will see the following output.

cros-img3

 

Now add a new project in the solutions and name it ServiceWebApp. Add AngularJS core package from the NuGet and add HTML page and name it Index.html.

cros-img5

Now add the following line of code in Index page.  In the index page, we add reference to our AngularJS library. And then create a module and a controller. And in the controller we are calling our ServiceAPI, which is hosted on a localhost but port number is different.  Now run the page and you will notice in the browser address bar the localhost port is different for your web application.  You will see the output in the browser no error but still the string return from Web API is not displayed.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>CORS - Sample Page</title>
    <script src="Scripts/angular.js" type="text/javascript"></script>
    <script type="text/javascript">
        var app = angular.module("corsapp", []);
        app.controller("corsController", function ($scope, $http) {
            $http.get("http://localhost:1445/api/serviceapi").
          success(function (data, status, headers, config) {
              $scope.cors = data;
          }).
          error(function (data, status, headers, config) {
              $scope.cors = data + "<br/>" + headers;
          });
        });
    </script>
</head>
<body ng-app="corsapp">
    <div ng-controller="corsController">
        <p>Calling Web API.</p>
        <h3>{{cors}}</h3>
    </div>
</body>
</html>

If you press F12 in chrome and see the developers tool window. Under Console tab you will see the below error.

XMLHttpRequest cannot load http://localhost:1445/api/serviceapi. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:1595' is therefore not allowed access.

You can see that our client call to the web API is not allowed. Because our both applications WebAPI and Web Site are running under different domains and when we try to call WebAPI cross browser security prevent our request.  To overcome this issue, right click on WebAPI project (CORS) and open Manage NuGet Pakcages window and search for CORS. You will find the WebAPI CORS package Microsoft.AspNet.WebApi.Cors. Install the package. And add the following line config.EnableCors(); in WebApiConfig file (You will find this file under App_Start folder). Our next step is to add EnableCors attribute on ServiceAPIController class [EnableCors(“http://localhost:1595”, “*”, “*”)] .  EnableCors attribute takes three parameters. In first we give the URL of the origin from where the call will be received. In our case it will be our Web Application URL. Second and third parameter we will put “*”.  Because we will want to allow all methods and headers. Do not include a forward slash at the end of the origins URL.

Now compile and run your WebAPI project. There is no change required at in Web Application project. So just refresh your web page (index.html).  And you will see the following output.

cros-img6

 

You can download the code from here.CORS-SourceCode

Leave a Reply