December 2013

Volume 28 Number 12

ASP.NET Web API - CORS Support in ASP.NET Web API 2

By Brock Allen | December 2013

Cross-origin resource sharing (CORS) is a World Wide Web Consortium (W3C) specification (commonly considered part of HTML5) that lets JavaScript overcome the same-origin policy security restriction imposed by browsers. The same-origin policy means that your JavaScript can only make AJAX calls back to the same origin of the containing Web page (where “origin” is defined as the combination of host name, protocol and port number). For example, JavaScript on a Web page from http://foo.com can’t make AJAX calls to http://bar.com (or to http://www.foo.com, https://foo.com or http://foo.com:999, for that matter).

CORS relaxes this restriction by letting servers indicate which origins are allowed to call them. CORS is enforced by browsers but must be implemented on the server, and the most recent release of ASP.NET Web API 2 has full CORS support. With Web API 2, you can configure policy to allow JavaScript clients from a different origin to access your APIs.

CORS Basics

To use the new CORS features in Web API, it’s helpful to understand the details of CORS itself, because the Web API implementation is true to the specification. These details might seem pedantic now, but they’ll be useful later to understand the available settings in Web API—and when you’re debugging CORS they’ll help you fix problems faster.

The general mechanics of CORS are such that when JavaScript is attempting to make a cross-origin AJAX call the browser will “ask” the server if this is allowed by sending headers in the HTTP request (for example, Origin). The server indicates what’s allowed by returning HTTP headers in the response (for example, Access-Control-Allow-Origin). This permission check is done for each distinct URL the client invokes, which means different URLs can have different permissions.

In addition to the origin, CORS lets a server indicate which HTTP methods are allowed, which HTTP request headers a client can send, which HTTP response headers a client can read, and if the browser is allowed to automatically send or receive credentials (cookies or authorization headers). Additional request and response headers indicate which of these features are allowed. These headers are summarized in Figure 1 (note that some of the features have no header sent in the request—only the response).

Figure 1 CORS HTTP Headers

Permission/Feature Request Header Response Header
Origin Origin Access-Control-Allow-Origin
HTTP method Access-Control-Request-Method Access-Control-Allow-Method
Request headers Access-Control-Request-Headers Access-Control-Allow-Headers
Response headers   Access-Control-Expose-Headers
Credentials   Access-Control-Allow-Credentials
Cache preflight response   Access-Control-Max-Age

Browsers can ask the server for these permissions in two different ways: simple CORS requests and preflight CORS requests.

Simple CORS Requests Here’s an example of a simple CORS request:

POST http://localhost/WebApiCorsServer/Resources/ HTTP/1.1
Host: localhost
Accept: */*
Origin: http://localhost:55912
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
value1=foo&value2=5

And the response:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Access-Control-Allow-Origin: http://localhost:55912
Content-Length: 27
{"Value1":"foo","Value2":5}

The request is a cross-origin request from http://localhost:55912 to http://localhost, and the browser adds an Origin HTTP header in the request to indicate the calling origin to the server. The server responds with an Access-­Control-Allow-Origin response header indicating that this origin is allowed. The browser enforces the server’s policy, and the JavaScript will receive its normal success callback.

The server can either respond with the exact origin value from the request or a value of “*” indicating any origin is allowed. If the server hadn’t allowed the calling origin, then the Access-Control-Allow-Origin header would simply be absent and the calling JavaScript’s error callback would be invoked.

Note that with a simple CORS request the call on the server is still invoked. This can be surprising if you’re still learning about CORS, but this behavior is no different from a scenario where the browser had constructed a <form> element and made a normal POST request. CORS doesn’t prevent the call from being invoked on the server; rather, it prevents the calling JavaScript from receiving the results. If you want to prevent the caller from invoking the server, then you’d implement some sort of authorization in your server code (possibly with the [Authorize] authorization filter attribute).

The preceding example is known as a simple CORS request because the type of AJAX call from the client was either a GET or a POST; the Content-Type was one of application/x-www-form-­urlencoded, multipart/form-data, or text/plain; and there were no additional request headers sent. If the AJAX call was another HTTP method, the Content-Type was some other value or the client wanted to send additional request headers, then the request would be considered a preflight request. The mechanics of preflight requests are slightly different.

Preflight CORS Requests If an AJAX call isn’t a simple request, then it requires a preflight CORS request, which is simply an additional HTTP request to the server to obtain permission. This preflight request is made automatically by the browser and uses the OPTIONS HTTP method. If the server responds successfully to the preflight request and grants permission, then the browser will perform the actual AJAX call the JavaScript is attempting to make.

If performance is a concern (and when isn’t it?), then the outcome of this preflight request can be cached by the browser by including the Access-Control-Max-Age header in the preflight response. The value contains the number of seconds for which the permissions can be cached.

Here’s an example of a preflight CORS request:

OPTIONS http://localhost/WebApiCorsServer/Resources/1 HTTP/1.1
Host: localhost
Access-Control-Request-Method: PUT
Origin: http://localhost:55912
Access-Control-Request-Headers: content-type
Accept: */*

And the preflight response:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost:55912
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Headers: content-typeAccess-Control-Max-Age: 600

Here’s the actual AJAX request:

PUT http://localhost/WebApiCorsServer/Resources/1 HTTP/1.1
Host: localhost
Content-Length: 27
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://localhost:55912
Content-Type: application/json
{"value1":"foo","value2":5}

And the AJAX response:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Access-Control-Allow-Origin: http://localhost:55912
Content-Length: 27
{"Value1":"foo","Value2":5}

Notice in this example a preflight CORS request is triggered because the HTTP method is PUT and the client needs to send the Content-Type header to indicate that the request contains application/json. In the preflight request (in addition to Origin) the Access-Control-Request-Method and Access-Control-Request-Headers request headers are used to ask for permission for the type of HTTP method and the additional header the client wishes to send.

The server granted permission (and set a preflight cache duration) and then the browser allowed the actual AJAX call. If the server didn’t grant permission to any of the requested features, then the corresponding response header would’ve been absent, the AJAX call wouldn’t have been made and the JavaScript error callback would’ve been invoked instead.

The preceding HTTP requests and responses were made using Firefox. If you were to use Internet Explorer, then you’d notice an additional Accept header being requested. If you were to use Chrome, you’d see both Accept and Origin additionally requested. Interestingly, you won’t see Accept or Origin in the Access-Control-­Allow-Headers, as the specification says they’re implied and can be omitted (which Web API does). It’s a point of debate if Origin and Accept actually need to be requested, but given how these browsers work today, your Web API CORS policy will most likely need to include them. It’s unfortunate that browser vendors don’t seem to be consistent in their reading of the specification.

Response Headers It’s easy to give a client permission to access response headers using the Access-Control-Expose-Headers response header. Here’s an example of an HTTP response that allows the calling JavaScript to access the custom response header “bar”:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Access-Control-Allow-Origin: http://localhost:55912Access-Control-Expose-Headers: bar
bar: a bar value
Content-Length: 27
{"Value1":"foo","Value2":5}

The JavaScript client can simply use the XMLHttpRequest getResponseHeader function to read the value. Here’s an example using jQuery:

$.ajax({
  url: "http://localhost/WebApiCorsServer/Resources/1",
  // other settings omitted
}).done(function (data, status, xhr) {
  var bar = xhr.getResponseHeader("bar");
  alert(bar);
});

Credentials and Authentication Possibly the most confusing aspect of CORS has to do with credentials and authentication. Generally, authentication with Web APIs can be done either with a cookie or with an Authorization header (there are other ways, but these two are the most common). In normal browser activity, if one of these has been previously established, then the browser will implicitly pass these values to the server on subsequent requests. With cross-origin AJAX, though, this implicit passing of the values must be explicitly requested in JavaScript (via the withCredentials flag on the XMLHttpRequest) and must be explicitly allowed in the server’s CORS policy (via the Access-Control-Allow-Credentials response header).

Here’s an example of a JavaScript client setting the withCredentials flag with jQuery:

$.ajax({
  url: "http://localhost/WebApiCorsServer/Resources/1",
  xhrFields: {
    withCredentials: true
  }
  // Other settings omitted
});

The withCredentials flag does two things: If the server issues a cookie, the browser can accept it; if the browser has a cookie, it can send it to the server.

Here’s an example of the HTTP response allowing credentials:

HTTP/1.1 200 OK
Set-Cookie: foo=1379020091825
Access-Control-Allow-Origin: http://localhost:55912
Access-Control-Allow-Credentials: true

The Access-Control-Allow-Credentials response header does two things: If the response has a cookie, the browser can accept it; and if the browser sent a cookie on the request, the JavaScript client can receive the results of the call. In other words, if the client sets withCredentials, then the client will only see a success callback in the JavaScript if the server (in the response) allows credentials. If withCredentials was set and the server doesn’t allow credentials, the client won’t get access to the results and the client error callback will be invoked.

The same set of rules and behaviors apply if the Authorization header is used instead of cookies (for example, when using Basic or Integrated Windows authentication). An interesting note about using credentials and the Authorization header: The server doesn’t have to explicitly grant the Authorization header in the Access-Control-Allow-Headers CORS response header.

Note that with the Access-Control-Allow-Credentials CORS response header, if the server issues this header, then the wildcard value of “*” can’t be used for Access-Control-Allow-Origin. Instead the CORS specification requires the explicit origin to be used. The Web API framework handles all of this for you, but I mention it here because you might notice this behavior while debugging.

There’s an interesting twist to this discussion of credentials and authentication. The description up to this point has been for the scenario where the browser is implicitly sending credentials. It’s possible for a JavaScript client to explicitly send credentials (again, typically via the Authorization header). If this is the case, then none of the aforementioned rules or behaviors related to credentials applies.

For this scenario, the client would explicitly set the Authorization header on the request and wouldn’t need to set withCredentials on the XMLHttpRequest. This header would trigger a preflight request and the server would need to allow the Authorization header with the Access-Control-Allow-Headers CORS response header. Also, the server wouldn’t need to issue the Access-Control-­Allow-Credentials CORS response header.

Here’s what that client code would look like to explicitly set the Authorization header:

$.ajax({
  url: "http://localhost/WebApiCorsServer/Resources/1",
  headers: {
    "Authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3Mi..."
  }
  // Other settings omitted
});

Here’s the preflight request:

OPTIONS http://localhost/WebApiCorsServer/Resources/1 HTTP/1.1
Host: localhost
Access-Control-Request-Method: GET
Origin: http://localhost:55912
Access-Control-Request-Headers: authorization
Accept: */*

Here’s the preflight response:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: authorization

Explicitly setting a token value in the Authorization header is a safer approach to authentication because you avoid the possibility of cross-site request forgery (CSRF) attacks. You can see this approach in the new Single-Page Application (SPA) templates in Visual Studio 2013.

Now that you’ve seen the basics of CORS at the HTTP level, I’ll show you how to use the new CORS framework to emit these headers from Web API.

CORS Support in Web API 2

The CORS support in Web API is a full framework for allowing an application to define the permissions for CORS requests. The framework revolves around the concept of a policy that lets you specify the CORS features to be allowed for any given request into the application.

First, in order to get the CORS framework, you must reference the CORS libraries from your Web API application (they’re not referenced by default from any of the Web API templates in Visual Studio 2013). The Web API CORS framework is available via NuGet as the Microsoft.AspNet.WebApi.Cors package. If you’re not using NuGet, it’s also available as part of Visual Studio 2013, and you’ll need to reference two assemblies: System.Web.Http.Cors.dll and System.Web.Cors.dll (on my machine these are located in C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET Web Stack 5\Packages).

Next, to express the policy, Web API provides a custom attribute class called EnableCorsAttribute. This class contains properties for the allowed origins, HTTP methods, request headers, response headers and whether credentials are allowed (which model all of the details of the CORS specification discussed earlier).

Finally, in order for the Web API CORS framework to process CORS requests and emit the appropriate CORS response headers, it must look at every request into the application. Web API has an extensibility point for such interception via message handlers. Appropriately, the Web API CORS framework implements a message handler called CorsMessageHandler. For CORS requests, it will consult the policy expressed in the attribute for the method being invoked and emit the appropriate CORS response headers.

EnableCorsAttribute The EnableCorsAttribute class is how an application can express its CORS policy. The EnableCorsAttribute class has an overloaded constructor that can accept either three or four parameters. The parameters (in order) are:

  1. List of origins allowed
  2. List of request headers allowed
  3. List of HTTP methods allowed
  4. List of response headers allowed (optional)

There’s also a property for allowing credentials (Supports­Credentials) and another for specifying the preflight cache duration value (PreflightMaxAge).

Figure 2 shows an example of applying the EnableCors attribute to individual methods on a controller. The values being used for the various CORS policy settings should match the CORS requests and responses that were shown in the prior examples.

Figure 2 Applying the EnableCors Attribute to Action Methods

public class ResourcesController : ApiController
{
  [EnableCors("http://localhost:55912", // Origin
              null,                     // Request headers
              "GET",                    // HTTP methods
              "bar",                    // Response headers
              SupportsCredentials=true  // Allow credentials
  )]
  public HttpResponseMessage Get(int id)
  {
    var resp = Request.CreateResponse(HttpStatusCode.NoContent);
    resp.Headers.Add("bar", "a bar value");
    return resp;
  }
  [EnableCors("http://localhost:55912",       // Origin
              "Accept, Origin, Content-Type", // Request headers
              "PUT",                          // HTTP methods
              PreflightMaxAge=600             // Preflight cache duration
  )]
  public HttpResponseMessage Put(Resource data)
  {
    return Request.CreateResponse(HttpStatusCode.OK, data);
  }
  [EnableCors("http://localhost:55912",       // Origin
              "Accept, Origin, Content-Type", // Request headers
              "POST",                         // HTTP methods
              PreflightMaxAge=600             // Preflight cache duration
  )]
  public HttpResponseMessage Post(Resource data)
  {
    return Request.CreateResponse(HttpStatusCode.OK, data);
  }
}

Notice each of the constructor parameters is a string. Multiple values are indicated by specifying a comma-separated list (as is specified for the allowed request headers in Figure 2). If you wish to allow all origins, request headers or HTTP methods, you can use a “*” as the value (you must still be explicit for response headers).

In addition to applying the EnableCors attribute at the method level, you can also apply it at the class level or globally to the application. The level at which the attribute is applied configures CORS for all requests at that level and below in your Web API code. So, for example, if applied at the method level, the policy will only apply to requests for that action, whereas if applied at the class level, the policy will be for all requests to that controller. Finally, if applied globally, the policy will be for all requests.

Following is another example of applying the attribute at the class level. The settings used in this example are quite permissive because the wildcard is used for the allowed origins, request headers and HTTP methods:

[EnableCors("*", "*", "*")]
public class ResourcesController : ApiController
{
  public HttpResponseMessage Put(Resource data)
  {
    return Request.CreateResponse(HttpStatusCode.OK, data);
  }
  public HttpResponseMessage Post(Resource data)
  {
    return Request.CreateResponse(HttpStatusCode.OK, data);
  }
}

If there’s a policy at multiple locations, the “closest” attribute is used and the others are ignored (so the precedence is method, then class, then global). If you’ve applied the policy at a higher level but then wish to exclude a request at a lower level, you can use another attribute class called DisableCorsAttribute. This attribute, in essence, is a policy with no permissions allowed.

If you have other methods on the controller where you don’t want to allow CORS, you can use one of two options. First, you can be explicit in the HTTP method list, as shown in Figure 3. Or you can leave the wildcard, but exclude the Delete method with the DisableCors attribute, as shown in Figure 4.

Figure 3 Using Explicit Values for HTTP Methods

[EnableCors("*", "*", "PUT, POST")]
public class ResourcesController : ApiController
{
  public HttpResponseMessage Put(Resource data)
  {
    return Request.CreateResponse(HttpStatusCode.OK, data);
  }
  public HttpResponseMessage Post(Resource data)
  {
    return Request.CreateResponse(HttpStatusCode.OK, data);
  }
  // CORS not allowed because DELETE is not in the method list above
  public HttpResponseMessage Delete(int id)
  {
    return Request.CreateResponse(HttpStatusCode.NoContent);
  }
}

Figure 4 Using the DisableCors Attribute

[EnableCors("*", "*", "*")]
public class ResourcesController : ApiController
{
  public HttpResponseMessage Put(Resource data)
  {
    return Request.CreateResponse(HttpStatusCode.OK, data);
  }
  public HttpResponseMessage Post(Resource data)
  {
    return Request.CreateResponse(HttpStatusCode.OK, data);
  }
  // CORS not allowed because of the [DisableCors] attribute
  [DisableCors]
  public HttpResponseMessage Delete(int id)
  {
    return Request.CreateResponse(HttpStatusCode.NoContent);
  }
}

CorsMessageHandler The CorsMessageHandler must be enabled for the CORS framework to perform its job of intercepting requests to evaluate the CORS policy and emit the CORS response headers. Enabling the message handler is typically done in the application’s Web API configuration class by invoking the EnableCors extension method:

public static class WebApiConfig
{
  public static void Register(HttpConfiguration config)
  {
    // Other configuration omitted
    config.EnableCors();
  }
}

If you wish to provide a global CORS policy, you can pass an instance of the EnableCorsAttribute class as a parameter to the EnableCors method. For example, the following code would configure a permissive CORS policy globally within the application:

public static class WebApiConfig
{
  public static void Register(HttpConfiguration config)
  {
    // Other configuration omitted
    config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
  }
}

As with any message handler, the CorsMessageHandler can alternatively be registered per-route rather than globally.

So that’s it for the basic, “out of the box” CORS framework in ASP.NET Web API 2. One nice thing about the framework is that it’s extensible for more dynamic scenarios, which I’ll look at next.

Customizing Policy

It should be obvious from the earlier examples that the list of origins (if the wildcard isn’t being used) is a static list compiled into the Web API code. While this might work during development or for specific scenarios, it isn’t sufficient if the list of origins (or other permissions) needs to be determined dynamically (say, from a database).

Fortunately, the CORS framework in Web API is extensible such that supporting a dynamic list of origins is easy. In fact, the framework is so flexible that there are two general approaches for customizing the generation of policy.

Custom CORS Policy Attribute One approach to enable a dynamic CORS policy is to develop a custom attribute class that can generate the policy from some data source. This custom attribute class can be used instead of the EnableCorsAttribute class provided by Web API. This approach is simple and retains the fine-grained feel of being able to apply an attribute on specific classes and methods (and not apply it on others), as needed.

To implement this approach, you simply build a custom attribute similar to the existing EnableCorsAttribute class. The main focus is the ICorsPolicyProvider interface, which is responsible for creating an instance of a CorsPolicy for any given request. Figure 5 contains an example.

Figure 5 A Custom CORS Policy Attribute

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,
                AllowMultiple = false)]
public class EnableCorsForPaidCustomersAttribute :
  Attribute, ICorsPolicyProvider
{
  public async Task<CorsPolicy> GetCorsPolicyAsync(
    HttpRequestMessage request, CancellationToken cancellationToken)
  {
    var corsRequestContext = request.GetCorsRequestContext();
    var originRequested = corsRequestContext.Origin;
    if (await IsOriginFromAPaidCustomer(originRequested))
    {
      // Grant CORS request
      var policy = new CorsPolicy
      {
        AllowAnyHeader = true,
        AllowAnyMethod = true,
      };
      policy.Origins.Add(originRequested);
      return policy;
    }
    else
    {
      // Reject CORS request
      return null;
    }
  }
  private async Task<bool> IsOriginFromAPaidCustomer(
    string originRequested)
  {
    // Do database look up here to determine if origin should be allowed
    return true;
  }
}

The CorsPolicy class has all the properties to express the CORS permissions to grant. The values used here are just an example, but presumably they could be populated dynamically from a database query (or from any other source).

Custom Policy Provider Factory The second general approach to building a dynamic CORS policy is to create a custom policy provider factory. This is the piece of the CORS framework that obtains the policy provider for the current request. The default implementation from Web API uses the custom attributes to discover the policy provider (as you saw earlier, the attribute class itself was the policy provider). This is another pluggable piece of the CORS framework, and you’d implement your own policy provider factory if you wanted to use an approach for policy other than custom attributes.

The attribute-based approach described earlier provides an implicit association from a request to a policy. A custom policy provider factory approach is different from the attribute approach because it requires your implementation to provide the logic to match the incoming request to a policy. This approach is more coarse-grained, as it’s essentially a centralized approach for obtaining a CORS policy.

Figure 6 shows an example of what a custom policy provider factory might look like. The main focus in this example is the implementation of the ICorsPolicyProviderFactory interface and its GetCorsPolicyProvider method.

Figure 6 A Custom Policy Provider Factory

public class DynamicPolicyProviderFactory : ICorsPolicyProviderFactory
{
  public ICorsPolicyProvider GetCorsPolicyProvider(
    HttpRequestMessage request)
  {
    var route = request.GetRouteData();
    var controller = (string)route.Values["controller"];
    var corsRequestContext = request.GetCorsRequestContext();
    var originRequested = corsRequestContext.Origin;
    var policy = GetPolicyForControllerAndOrigin(
      controller, originRequested);
    return new CustomPolicyProvider(policy);
  }
  private CorsPolicy GetPolicyForControllerAndOrigin(
   string controller, string originRequested)
  {
    // Do database lookup to determine if the controller is allowed for
    // the origin and create CorsPolicy if it is (otherwise return null)
    var policy = new CorsPolicy();
    policy.Origins.Add(originRequested);
    policy.Methods.Add("GET");
    return policy;
  }
}
public class CustomPolicyProvider : ICorsPolicyProvider
{
  CorsPolicy policy;
  public CustomPolicyProvider(CorsPolicy policy)
  {
    this.policy = policy;
  }
  public Task<CorsPolicy> GetCorsPolicyAsync(
    HttpRequestMessage request, CancellationToken cancellationToken)
  {
    return Task.FromResult(this.policy);
  }
}

The main difference in this approach is that it’s entirely up to the implementation to determine the policy from the incoming request. In Figure 6, the controller and origin could be used to query a database for the policy values. Again, this approach is the most flexible, but it potentially requires more work to determine the policy from the request.

To use the custom policy provider factory, you must register it with Web API via the SetCorsPolicyProviderFactory extension method in the Web API configuration:

public static class WebApiConfig
{
  public static void Register(HttpConfiguration config)
  {
    // Other configuration omitted
    config.EnableCors();
    config.SetCorsPolicyProviderFactory(
      new DynamicPolicyProviderFactory());
  }
}

Community Contributions in Action

ASP.NET Web API is an open source framework and is part of a larger set of open source frameworks collectively called the ASP.NET Web Stack, which also includes MVC, Web Pages and others.

These frameworks are used to build the ASP.NET platform and are curated by the ASP.NET team at Microsoft. As curator of an open source platform, the ASP.NET team welcomes community contributions, and the cross-origin resource sharing (CORS) implementation in Web API is one such contribution.

It was originally developed by Brock Allen as part of the thinktecture IdentityModel security library (thinktecture.github.io).

Debugging CORS

A few techniques come to mind to debug CORS if (and when) your cross-origin AJAX calls aren’t working.

Client Side One approach to debugging is to simply use your HTTP debugger of choice (for example, Fiddler) and inspect all HTTP requests. Armed with the knowledge gleaned earlier about the details of the CORS specification, you can usually sort out why a particular AJAX request isn’t being granted permission by inspecting the CORS HTTP headers (or lack thereof).

Another approach is to use your browser’s F12 developer tools. The console window in modern browsers provides a useful error message when an AJAX calls fails due to CORS.

Server Side The CORS framework itself provides detailed trace messages using the tracing facilities of Web API. As long as an ITraceWriter is registered with Web API, the CORS framework will emit messages with information about the policy provider selected, the policy used, and the CORS HTTP headers emitted. For more information on Web API tracing, consult the Web API documentation on MSDN.

A Highly Requested Feature

CORS has been a highly requested feature for some time now, and finally it’s built in to Web API. This article focuses heavily on the details of CORS itself, but that knowledge is crucial in implementing and debugging CORS. Armed with this knowledge, you should be able to easily utilize the CORS support in Web API to allow cross-origin calls in your applications.


Brock Allen is a consultant specializing in the Microsoft .NET Framework, Web development and Web-based security. He’s also an instructor for the training company DevelopMentor, associate consultant for thinktecture GmbH & Co. KG, a contributor to thinktecture open source projects and a contributor to the ASP.NET platform. You can reach him at his Web site, brockallen.com, or e-mail him at brockallen@gmail.com.

Thanks to the following technical expert for reviewing this article: Yao Huan Lin (Microsoft)
Yao Huang Lin (yaohuang@microsoft.com) is a software developer on the ASP.NET Web API team at Microsoft. He has worked on many components of the .NET Framework, including ASP.NET, Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF).