Using StaticFileOptions() breaks embedded static files from Razor Class Library

783 Views Asked by At

I'm trying to add long cache headers to static .css and .js files using StaticFileOptions

From various SO and other articles, this is how you do it:

app.UseStaticFiles(new StaticFileOptions
{
    OnPrepareResponse = ctx =>
    {
        const int durationInSeconds = 60 * 60 * 24;
        ctx.Context.Response.Headers[HeaderNames.CacheControl] =
        "public,max-age=" + durationInSeconds;
    }
}); 

However, I am using a bunch of static files provided by a RCL. The RCL has a StaticServing.cs class which I have used from this article: Can Razor Class Library pack static files (js, css etc) too?

For the sake of completeness to my question, this class is as follows:

public StaticServing(IHostingEnvironment environment)
    {
        Environment = environment;
    }
    public IHostingEnvironment Environment { get; }

    public void PostConfigure(string name, StaticFileOptions options)
    {
        name = name ?? throw new ArgumentNullException(nameof(name));
        options = options ?? throw new ArgumentNullException(nameof(options));

        // Basic initialization in case the options weren't initialized by any other component
        options.ContentTypeProvider = options.ContentTypeProvider ?? new FileExtensionContentTypeProvider();
        if (options.FileProvider == null && Environment.WebRootFileProvider == null)
        {
            throw new InvalidOperationException("Missing FileProvider.");
        }

        options.FileProvider = options.FileProvider ?? Environment.WebRootFileProvider; 

        string basePath = "Static";

        ManifestEmbeddedFileProvider filesProvider = new ManifestEmbeddedFileProvider(GetType().Assembly, basePath);
        options.FileProvider = new CompositeFileProvider(options.FileProvider, filesProvider);
    }
}

in the consuming projects startup.cs I have services.ConfigureOptions(typeof(StaticServing)); and the RCL has <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest> and <EmbeddedResource Include="Static\**\*" /> settings.

With this all in place everything works... UNLESS I add the StaticFileOptions code at the start of the question, in which case, all references to the embedded static files return 404.

I have tried adding:

  • FileProvider = env.ContentRootFileProvider and
  • FileProvider = env.WebRootFileProvider

To the StaticFileOptions setting, but that isn't working.

1

There are 1 best solutions below

0
On BEST ANSWER

The static files middleware can receive its StaticFileOptions in one of two ways:

  1. Implicitly via Dependency Injection.
  2. Explicitly via the call to UseStaticFiles.

In your problematic scenario, you're (inadvertently) attempting to configure the middleware using both of these approaches. As soon as you add an argument to the UseStaticFiles call, you're replacing the framework-provided configuration for the middleware, which includes setup for RCL support.

To build on the framework-provided configuration, you can take advantage of the options pattern in ConfigureServices:

services.Configure<StaticFileOptions>(options =>
{
    options.OnPrepareResponse = ctx =>
    {
        const int durationInSeconds = 60 * 60 * 24;
        ctx.Context.Response.Headers[HeaderNames.CacheControl] =
            "public, max-age=" + durationInSeconds;
    }  
});

You'll also need to remove the argument being passed to UseStaticFiles.