2

I am trying to enable static file caching but seems like no effect, at least in browser i could not find response header with name cache-control

This is my code

        app.UseSpaStaticFiles(new StaticFileOptions
        {
            RequestPath = _settings.SpaRoute,                
        });


            app.UseStaticFiles(new StaticFileOptions
            {
                OnPrepareResponse = ctx =>
                {
                    // Cache static files for 30 days
                    ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=2592000");
                    ctx.Context.Response.Headers.Append("Expires", DateTime.UtcNow.AddDays(30).ToString("R", CultureInfo.InvariantCulture));
                }
            });

After building and running my app in local env i got the following response headers

enter image description here

As you can see no cache control header represented here, what am i doing wrong?

5
  • Is there another app.UseStaticFiles before what's shown here? Commented Jul 22, 2021 at 11:58
  • Also, Cache-Control is enough by itself, no need for Expires: developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control, or its needless date arithmetic. Commented Jul 22, 2021 at 11:59
  • There are another app.UseSpaStaticFiles(); middleware before that Commented Jul 22, 2021 at 12:27
  • Updated code part in post Commented Jul 22, 2021 at 12:27
  • It is short-circuiting the request and sending a response before your code here has a chance to. Place the OnPrepareResponse inside the options you pass into UseSpaStaticFiles. Commented Jul 22, 2021 at 12:29

2 Answers 2

7

StaticFileMiddleware is a terminal middleware, i.e. it short-circuits the request and never calls the next middleware in chain if it comes across a static file request that doesn't match an endpoint (among other conditions).

This means if you have multiple calls to app.UseStaticFiles(), it will insert StaticFileMiddleware in the middleware chain more than once and only the first one in the chain will handle the request, the rest will stay dormant.

Put a breakpoint inside a controller action and check the call stack and see if there are more than one StaticFileMiddleware in the stack. If you do, remove the unused ones, or move the configuration you have here into the first one.

In your code, you seem to have app.UseSpaStaticFiles, which calls app.UseStaticFiles, so it's taking effect before your own app.UseStaticFiles(/*custom options*/).

To solve the problem, simply pass the OnPrepareResponse into that middleware:

app.UseSpaStaticFiles(new StaticFileOptions {
    RequestPath = _settings.SpaRoute, 
    OnPrepareResponse = ctx =>
    {
        // Cache static files for 30 days
        ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=2592000");
    }               
});
Sign up to request clarification or add additional context in comments.

5 Comments

One more question, let's say i have an image for my main site and i cache that image for a 1 year because i am not going to change for a long time . But after a while, in some day i have decide to change that image and take another one, what should i do in that case? Is there a mechanism to determine whether that file has been changed or no and load the new file and cache it?
You can add a version suffix to that asset that changes every time it's changed. Once the asset URL changes, browser will fetch the new file and cache that instead. For Razor templates, you have asp-append-version tag helper. For UI frameworks, it depends on what you use. If you're using webpack you can add version/hash to filenames webpack.js.org/guides/caching.
If all else fails you can simply append a version yourself: <img src="logo.svg" /> -> <img src="logo.svg?v=20210722" />
Thanks, can you pleasse explain logic behind this public,max-age=2592000 = 30 days ? What if i would like to cache only 3 day ? How this algorithms should be calculated?
You need to specify the duration in seconds: (3 days) * (24hr / day) * (60min / hr) * (60sec / min) = 259200 sec -> so you need to use public,max-age=259200. As for the meaning of other directives, MDN is a good starting point. developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
0

Use static files is sufficient, at least in .NET 6...

appBuilder.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(Path.Combine(AppContext.BaseDirectory, "wwwroot")),
    OnPrepareResponse = ctx =>
    {
        ctx.Context.Response.Headers["Cache-Control"] = "public, max-age: 604800";
    }
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.