ASP.NET Core is a great piece of technology and it's fun to develop with. At the moment I am working on a Tile Server in ASP.NET Core and I need to serve static files to a Vue.js application. The Vue.js development server is running on a different port. So what happens?
Cross Origin Resource Sharing (CORS)!
According to Microsoft CORS ...
- Is a W3C standard that allows a server to relax the same-origin policy.
- Is not a security feature, CORS relaxes security. An API is not safer by allowing CORS. For more information, see How CORS works.
- Allows a server to explicitly allow some cross-origin requests while rejecting others.
- Is safer and more flexible than earlier techniques, such as JSONP.
ASP.NET Core provides a CORS Middleware, that handles all the dirty work of configuring and handling CORS, which can
be easily added as a Service using the IServiceCollection#AddCors
extension and and integrated into the request
using the IApplicationBuilder#UseCors
extension.
The Problem
But there is a little twist in ASP.NET Core. If you are using the Static Files feature with the IApplicationBuilder
extension
method UseStaticFiles()
, then no CORS strategy is applied. So while we are able to serve all requests to Controllers with
CORS headers, all requests to static files from Vue.js with fail.
The Solution
We can use the OnPrepareResponse
to serve CORS headers, when configuring the Static Files Middleware. We are also injecting
the ICorsService
and ICorsPolicyProvider
into the Statup Configure
method. Then in the UseStaticFiles
you can
use the StaticFileOptions
to add additional headers in the OnPrepareResponse
method.
Here is the relevant snippet from the MapboxTileServer project.
namespace MapboxTileServer
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add CORS:
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", policyBuilder => policyBuilder
.WithOrigins("http://localhost:4200", "http://localhost:8080", "http://localhost:9000")
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
// ...
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ICorsService corsService, ICorsPolicyProvider corsPolicyProvider)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors("CorsPolicy");
// To serve PBF Files, we need to allow unknown filetypes
// to be served by the Webserver:
app.UseStaticFiles(new StaticFileOptions
{
ServeUnknownFileTypes = true,
OnPrepareResponse = (ctx) =>
{
var policy = corsPolicyProvider.GetPolicyAsync(ctx.Context, "CorsPolicy")
.ConfigureAwait(false)
.GetAwaiter().GetResult();
var corsResult = corsService.EvaluatePolicy(ctx.Context, policy);
corsService.ApplyResult(corsResult, ctx.Context.Response);
}
});
// ...
}
}
}