I was having issues with CORS whereby if I allow any method, any origin and any headers, everything worked fine, but the moment I constrain any of those the browser console instantly turned red.
I've since fixed my issue (it was due to a bad environment variable) but it was a rather tedious trial and error process.
Is there any way to diagnose CORS issues in .NET Core? Is the actual reason for the failure logged anywhere?
For the case above, it would've been very helpful if I could've found a log that said "preflight failed because origin was X but expected Y".
Any googling I do just seems to come up with either how to configure CORS or how to address specific problems.
The error Chrome was reporting was "No 'Access-control-allow-origin' header is present on the requested resource". But this question isn't about this error. The question is more general as in why the CORS preflight fails in general.
In this case, Chrome complained that 'Access-control-allow-origin' header wasn't set. I don't want this question to be about this specific error. Instead, what I want from this question is to determine if .NET Core has any logs that, using this case as an example, show WHY .NET Core did not include any Access-Control-Allow-Origin header.
In this particular case, the URL used when configuring CORS was retrieved from an environment variable. I was deploying on a test server. The environment variable on the test server was incorrectly set to the URL for the integration environment. Because of this, .NET Core on the TEST server was expecting requests from the INT frontend. Because the requests were coming from the TEST frontend (test environment URL), it did not match what .NET Core was expecting (it was incorrectly expecting the requests to come from the INT url). Because of this, .NET Core did not include the 'Access-control-allow-origin' header.
Does .NET Core log this anywhere? Does it have any logs which tell me "Will not include 'Access-control-allow-origin' header in the response because the origin from the request is 'bla di bla' but 'lorem ipsum' was expected".
Code used
public void ConfigureServices(IServiceCollection services)
{
// Other configurations...
// Enable CORS with named policy
services.AddCors(options =>
{
options.AddPolicy("MyCorsPolicy", builder =>
{
// Configure CORS policy as needed
builder.WithOrigins(GetFrontendUrlFromEnvironmentVariable())
.AllowAnyMethod()
.AllowAnyHeader();
});
});
}
public void Configure(IApplicationBuilder app)
{
app.UseCors("MyCorsPolicy");
// app.UseEndpoints( bla bla) and the rest;
}
It seems the real question is how to detect whether CORS was misconfigured. Logging can't show this. During setup in Program.cs or Startup.cs, the logging middleware itself isn't yet up.
Once the application starts, CORS does use logging, issuing messages in the Microsoft.AspNetCore.Cors category. All except FailedToSetCorsHeaders
are at Information
or bellow though and filtered out by the "Microsoft.AspNetCore":"Warning"
setting used by most web applications. The default logging settings in appsettings.json
are :
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
To enable more detailed logging one should add "Microsoft.AspNetCore.Cors":"Information"
. This will create a lot of noise though and shouldn't be used in production
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.AspNetCore.Cors":"Information"
}
},
"AllowedHosts": "*"
}
This can help up to a point, as it reports the results of policy checks, not what is sent to the browser or how the browser responds to it. It won't log how the CORS policies were set up or what they were.
To fix the original problem, an application should set up bootstrap a bootstrap logger, ie a logger used only during configuration, and log the various setup steps. This becomes a lot easier if the various configuration parts are extracted in their own methods or even classes.
For example, using a Serilog Bootstrap logger and separate CORS methods for each scenario, the application can log which one was configured, along with any settings :
Log.Logger = new LoggerConfiguration()
.WriteTo.Console() // + file or centralized logging
.CreateLogger();
IServiceCollection CorsForProduction(IServiceCollection services, string envronment, ...)
{
Log.Information("CORS for Production with {setting}",new {Environment=environment,...});
services.AddCors(options=>{
...
});
return services
}
IServiceCollection CorsForStaging(IServiceCollection services, string envronment, ...)
{
Log.Information("CORS for Staging with {setting}",new {Environment=environment,...});
services.AddCors(options=>{
....
});
return services
}