You know, the usual: CORS isn't working. Chrome serves me up with this:
Fetch API cannot load https://url-to-my-api-thing. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://url-to-the-origin-thing' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I have an ASP.NET Web API 2 application which uses the OWIN pipeline and is hosted in IIS.
Here's how I (try to) set up CORS in my Configuration
method:
// ... container setup above, CORS is the first middleware ...
var corsPolicyProvider = new CorsPolicyProvider(_corsOrigins, container.GetInstance<ILogger>);
app.UseCors(new CorsOptions
{
PolicyProvider = corsPolicyProvider
});
app.UseStageMarker(PipelineStage.Authenticate);
configuration.Services.Replace(typeof(IExceptionHandler), new PassThroughExceptionHandler());
configuration.MapHttpAttributeRoutes();
app.UseWebApi(configuration);
And here's what my CorsPolicyProvider
class looks like:
public class CorsPolicyProvider : ICorsPolicyProvider
{
private readonly Regex _corsOriginsRegex;
private readonly string _defaultCorsOrigin;
private readonly Func<ILogger> _scopedLoggerCreator;
public CorsPolicyProvider(string corsOrigins, Func<ILogger> scopedLoggerCreator)
{
_corsOriginsRegex = new Regex($"({corsOrigins})", RegexOptions.IgnoreCase);
_defaultCorsOrigin = corsOrigins?.Split('|').FirstOrDefault();
_scopedLoggerCreator = scopedLoggerCreator;
}
public Task<CorsPolicy> GetCorsPolicyAsync(IOwinRequest request)
{
var logger = _scopedLoggerCreator();
var allowedOrigin = _defaultCorsOrigin;
string[] origins;
request.Headers.TryGetValue("Origin", out origins);
var origin = origins?.FirstOrDefault();
if (origin != null && Uri.IsWellFormedUriString(origin, UriKind.Absolute) && _corsOriginsRegex.IsMatch(new Uri(origin).Host))
allowedOrigin = origins.FirstOrDefault();
var policy = new CorsPolicy
{
Origins = { allowedOrigin },
Methods = { HttpMethod.Get.Method, HttpMethod.Post.Method, HttpMethod.Put.Method, HttpMethod.Delete.Method },
Headers = { "accept", "content-type" },
SupportsCredentials = true,
PreflightMaxAge = 1728000
};
logger?.Verbose("Resolving CORS policy: {@CorsPolicy}", policy);
return Task.FromResult(policy);
}
}
Why is this policy never triggered, or at best malfunctioning? If I set a breakpoint and explicitly send an OPTIONS
request when testing locally, it enters the GetCorsPolicyAsync
method, and also logs the request as expected. But when the API is on the server and I try to call it from a website in Chrome, it never logs the request and it just tells me there's no CORS header.