Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Arjan H. 226 posts 463 karma points c-trib
    Nov 02, 2021 @ 20:01
    Arjan H.
    1

    Add Cache-Control header for static files (*.js, *.css, *.woff2, etc.)

    How can I set the Cache-Control header for static files (*.js, *.css, *.woff2, etc.)? I managed to set the header by adding the following code to the Configure() method of Startup.cs:

    var staticFileOptions = new StaticFileOptions()
    {
        OnPrepareResponse = context =>
        {
            string path = context.File.PhysicalPath;
            if (path.EndsWith(".css") || path.EndsWith(".js") || path.EndsWith(".svg") || path.EndsWith(".woff2"))
            {
                context.Context.Response.Headers.Add("Cache-Control", "public, max-age=31536000");
            }
        }
    };
    
    app.UseStaticFiles(staticFileOptions);
    

    However, this only works when add this code before the app.UseUmbraco(), but when I do that it breaks ImageSharp. When I add this code after app.UseUmbraco() the header is not being added to the response.

  • Arjan H. 226 posts 463 karma points c-trib
    Nov 02, 2021 @ 20:17
    Arjan H.
    1

    Adding the following code to Startup.cs before app.UseUmbraco() seems to do the trick. Need to do some more testing to see if this doesn't break anything.

    // Add Cache-Control header to static files
    app.Use(async (context, next) =>
    {
        string path = context.Request.Path;
    
        if (path.StartsWith("/umbraco/") == false)
        {
            if (path.EndsWith(".css") || path.EndsWith(".js") || path.EndsWith(".svg") || path.EndsWith(".woff2"))
            {
                context.Response.Headers.Add("Cache-Control", "public, max-age=31536000");
            }
        }
    
        await next();
    });
    
  • Joao Pinto 13 posts 34 karma points
    Jul 11, 2022 @ 16:31
    Joao Pinto
    0

    I tried your solution but is not working for static files (fonts, etc..). I am now testing with replacing app.UseStaticFiles on Startup.cs with the following code, seems to work

    app.UseStaticFiles(new StaticFileOptions
            {
                OnPrepareResponse = ctx =>
                {
                    ctx.Context.Response.Headers[HeaderNames.CacheControl] =
                        "public,max-age=31536000";
                }
            });
    
  • Arjan H. 226 posts 463 karma points c-trib
    Jul 11, 2022 @ 18:06
    Arjan H.
    0

    I think it’s safer to exclude the /umbraco folder.

  • Joao Pinto 13 posts 34 karma points
    Jul 11, 2022 @ 18:56
    Joao Pinto
    0

    Why do you think so? Static files used by the backoffice aren't supposed to change too, isn't it?

  • Arjan H. 226 posts 463 karma points c-trib
    Jul 11, 2022 @ 19:19
    Arjan H.
    0

    Doesn’t Umbraco already set its own cache-control header for /umbraco and package files etc.? Or are all the backoffice file caches properly invalidated using querystring or based on another cache busting technique? I would think you don’t want to enforce a very strict cache protocol for the backoffice files to prevent issues after updating Umbraco or one of the packages.

    I also change the max-age for frontend files to improve page load and PageSpeed Insights scores. But for the backoffice I’d rather use no cache than adding a cache protocol that could potentially cause issues after upgrading Umbraco of packages.

  • Arjan H. 226 posts 463 karma points c-trib
    Jul 12, 2022 @ 13:33
    Arjan H.
    0

    Also, did you test to see if your solution does not interfere with ImageSharp? If it doesn't I'm curious to hear when you're calling UseStaticFiles() in Startup.cs.

  • Joey Kincer 51 posts 83 karma points
    Jul 23, 2022 @ 22:03
    Joey Kincer
    0

    Hey guys,

    Having a hell of a time trying to get both ImageSharp and static file cache-control working at the same time.

    I'm using Joao's app.UseStaticFiles code above in StartUp.cs. However if it's placed before app.UseUmbraco() then ImageSharp breaks and images can no longer be manipulated via query string. If it's placed after app.UseUmbraco(), then ImageSharp works again but all static files fail to be cached.

    I tried those path.StartsWith and EndWith conditionals but that didn't seem to make any difference. What is the best way to configure StartUp.cs so all files as well as any images not being manipulated by ImageSharp are cached?

  • Arjan H. 226 posts 463 karma points c-trib
    Jul 24, 2022 @ 14:20
  • Joey Kincer 51 posts 83 karma points
    Jul 24, 2022 @ 14:48
    Joey Kincer
    1

    Yeah I finally tried that last night and it seems to work OK. I came to the conclusion we just have to throw out UseStaticFiles() completely in order to utilize crops and ImageSharp manipulation while maintaining content-cache.

  • Pascal D. 2 posts 72 karma points
    Aug 16, 2022 @ 12:18
    Pascal D.
    0

    I was having the same issue. My solution was to use the app.UseWhen() conditional mapper, to exclude the media and umbraco paths. This must be done before the app.UseUmbraco()

    app.UseWhen(
        context => !context.Request.Path.StartsWithSegments("/umbraco") && !context.Request.Path.StartsWithSegments("/media"),
        appBuilder => appBuilder.UseStaticFiles(new StaticFileOptions())
    );
    

    I hope that helps.

  • Joao Pinto 13 posts 34 karma points
    Aug 17, 2022 @ 17:05
    Joao Pinto
    0

    Hey Pascal, I just tested your solution on Umbraco 10 and it works great! Thank you!

    The only problem I have right now is with Smidge js/css files. For some reason Smidge is overwriting whatever cache header I set with: cache-control: public, max-age=864000, s-maxage=864000

    Anyone has figured out a way to change max-age on Smidge generated files?

  • Vasco Horta e Costa 18 posts 119 karma points
    Jun 21, 2023 @ 10:21
    Vasco Horta e Costa
    0

    Hi João

     services.Configure<SmidgeOptions>(options =>
                {
                    options.DefaultBundleOptions.ProductionOptions.CacheControlOptions.CacheControlMaxAge = 365*24;
                });
    

    This worked for me

  • Joao Pinto 13 posts 34 karma points
    Jun 21, 2023 @ 13:26
    Joao Pinto
    0

    Hello Vasco,

    thanks for your input, I didn't test it as in the meantime we just applied another solution. Basically we forked Smidge and did the change in the source code to hard code the cache header to whatever we want.

  • David Armitage 510 posts 2081 karma points
    May 06, 2024 @ 08:46
    David Armitage
    0

    Did anyone find a solution for this?

    That is happening for me with Umbraco 13. Basically when UseStaticFiles is enabled in statup.cs the Image Processor does nothing.

    Pascal's work around did the trick but I am not sure thats the right solution. This would mean that static caching simply will not be applied to add images within the media folder.

    Surely that cant be Umbraco's recommended way around this?

  • Bjarne Fyrstenborg 1285 posts 4039 karma points MVP 8x c-trib
    May 06, 2024 @ 09:11
  • Arjan H. 226 posts 463 karma points c-trib
    May 06, 2024 @ 09:50
    Arjan H.
    1

    I'm currently using the following solution on an Umbraco 13 site and everything seems to be working just fine. The Cache-Control header is being added to CSS, JS, fonts, images and /media files.

    // Add Cache-Control header to static files
    builder.Services.Configure<StaticFileOptions>(options =>
    {
        options.OnPrepareResponse = ctx =>
        {
            // Skip files from Umbraco backoffice / packages
            if (ctx.Context.Request.Path.StartsWithSegments("/umbraco") || ctx.Context.Request.Path.StartsWithSegments("/App_Plugins"))
                return;
    
            // Set specific cache-control response header
            var responseHeaders = ctx.Context.Response.GetTypedHeaders();
            var cacheControl = responseHeaders.CacheControl ?? new CacheControlHeaderValue();
    
            cacheControl.Public = true;
            cacheControl.MaxAge = TimeSpan.FromSeconds(31536000);
            responseHeaders.CacheControl = cacheControl;
        };
    });
    

    This needs to be called before builder.Build().

  • David Armitage 510 posts 2081 karma points
    May 06, 2024 @ 09:56
    David Armitage
    0

    Arjan,

    Is this in the ConfigureServices method or the Configure method. Can you share a little more of the setup.cs file.

    I want to double check exactly where you have this

  • Arjan H. 226 posts 463 karma points c-trib
    May 06, 2024 @ 10:04
    Arjan H.
    0

    I'm only using a Program.cs, see this blog post.

    WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
    
    var config = builder.Configuration;
    
    builder.CreateUmbracoBuilder()
        .AddBackOffice()
        .AddWebsite()
        .AddDeliveryApi()
        .AddComposers()
        //.SetContentLastChanceFinder<PageNotFoundContentFinder>()
        .Build();
    
    // Register custom services
    builder.RegisterApplicationServices(config);
    
    WebApplication app = builder.Build();
    
    await app.BootUmbracoAsync();
    
    // Configure custom middleware after Umbraco boot
    app.ConfigureMiddleware(config);
    
    app.UseUmbraco()
        .WithMiddleware(u =>
        {
            u.UseBackOffice();
            u.UseWebsite();
        })
        .WithEndpoints(u =>
        {
            u.UseInstallerEndpoints();
            u.UseBackOfficeEndpoints();
            u.UseWebsiteEndpoints();
        });
    
    // Show config debug information
    app.SetDebugInfoEndpoint(config);
    
    await app.RunAsync();
    

    The Cache-Control code is inside my custom RegisterApplicationServices() extension method:

    namespace Application.Core.Startup
    {
        public static class ServicesInitializer
        {
            public static WebApplicationBuilder RegisterApplicationServices(
                this WebApplicationBuilder builder,
                ConfigurationManager config)
            {
                [...]
    
                // Add Cache-Control header to static files
                builder.Services.Configure<StaticFileOptions>(options =>
                {
                    options.OnPrepareResponse = ctx =>
                    {
                        // Skip files from Umbraco backoffice / packages
                        if (ctx.Context.Request.Path.StartsWithSegments("/umbraco") || ctx.Context.Request.Path.StartsWithSegments("/App_Plugins"))
                            return;
    
                        // Set specific cache-control response header
                        var responseHeaders = ctx.Context.Response.GetTypedHeaders();
                        var cacheControl = responseHeaders.CacheControl ?? new CacheControlHeaderValue();
    
                        cacheControl.Public = true;
                        cacheControl.MaxAge = TimeSpan.FromSeconds(31536000);
                        responseHeaders.CacheControl = cacheControl;
                    };
                });
    
                [...]
            }
        }
    }
    
Please Sign in or register to post replies

Write your reply to:

Draft