May 11, 2015

Enabling CORS in ASP.NET Web API 2

We recently completed an upgrade of one of our APIs to Web API 2. Previously we were using a CORS implementation for Web API v1 by Brock Allen which later paved the way for the support in Web API v2.

CORS can be enabled using a Web API specific package (which uses message handlers) or OWIN Middleware. Which one to use will largely depend on your requirements:

When to use the Web API CORS package

  • You need fine grained control over CORS at the controller or action level (your API resources). For example, you may wish to allow different origins/HTTP methods per resource.

You can find a tutorial covering how to configure the Web API CORS package here.

When to use the CORS OWIN middleware

  • You’re using the OAuth middleware and need to authenticate client-side requests from another domain (origin).
  • You want to enable CORS for all of your middleware components.

We decided to use the OWIN middleware. Detailed documentation is a little thin on the ground with most examples just allowing all origins and HTTP methods:

app.UseCors(CorsOptions.AllowAll)

For finer grained control you can provide your own CorsPolicy:

public override void Register()
{
    var corsPolicy = new CorsPolicy
    {
        AllowAnyMethod = true,
        AllowAnyHeader = true
    };

    // Try and load allowed origins from web.config
    // If none are specified we'll allow all origins

    var origins = ConfigurationManager.AppSettings[Constants.CorsOriginsSettingKey];

    if (origins != null)
    {
        foreach (var origin in origins.Split(';'))
        {
            corsPolicy.Origins.Add(origin);
        }
    }
    else
    {
        corsPolicy.AllowAnyOrigin = true;
    }

    var corsOptions = new CorsOptions
    {
        PolicyProvider = new CorsPolicyProvider
        {
            PolicyResolver = context => Task.FromResult(corsPolicy)
        }
    };

    app.UseCors(corsOptions);
}

The CorsOptions class has a PolicyProvider property which determines how the CorsPolicy for the request will be resolved. This is how you could provide resource specific CORS policies but it’s not quite as nice to use as the attribute based Web API package.

Don’t forget to allow OPTIONS

One thing that caught me out after enabling the middleware is that IIS was intercepting pre-flight requests. To ensure ASP.NET handles OPTION requests, add the following in web.config:

<system.webServer>
  <handlers>
    <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
    <remove name="OPTIONSVerbHandler" />
    <remove name="TRACEVerbHandler" />
    <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
  </handlers>
</system.webServer>

© 2022 Ben Foster