We have a very specific business requirement where updated PDFs/Word/Excel files need to be immediately available on the website. On older versions of Umbraco I knew how to disable caching for /media/ path but I am not managing to find a good solution for version 13 (and eventually 17). Ideally caching would be disabled only for PDFs/Word/Excel and not for images. Would anyone know where I should look?
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Headers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Hosting;
using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment;
namespace Umbraco.Docs.Samples.Web.Tutorials;
public class ConfigureStaticFileOptions : IConfigureOptions<StaticFileOptions>
{
// These are the starting segments of the paths we want to cache
private static readonly HashSet<string> _cachedFilePaths = new(StringComparer.OrdinalIgnoreCase)
{
"/css","/styles","/scripts","/js","/images","/fonts", "/app_plugins"
};
private readonly string _backOfficePath;
private readonly bool _isDevelopmentEnv;
public ConfigureStaticFileOptions(IOptions<GlobalSettings> globalSettings, IHostingEnvironment hostingEnvironment, IWebHostEnvironment env)
{
_backOfficePath = hostingEnvironment.GetBackOfficePath(); ;
_isDevelopmentEnv = env.IsDevelopment();
}
public void Configure(StaticFileOptions options)
=> options.OnPrepareResponse = ctx =>
{
// if we are in development
if (_isDevelopmentEnv)
{
return;
}
// Exclude Umbraco backoffice assets
if (ctx.Context.Request.Path.StartsWithSegments(_backOfficePath))
{
return;
}
if (_cachedFilePaths.Any(s => ctx.Context.Request.Path.StartsWithSegments(s, StringComparison.OrdinalIgnoreCase)))
{
ResponseHeaders headers = ctx.Context.Response.GetTypedHeaders();
// Update or set Cache-Control header
CacheControlHeaderValue cacheControl = headers.CacheControl ?? new CacheControlHeaderValue();
cacheControl.Public = true;
cacheControl.MaxAge = TimeSpan.FromDays(30);
headers.CacheControl = cacheControl;
}
};
public class ResponseCacheingComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
=> builder.Services.AddTransient<IConfigureOptions<StaticFileOptions>, ConfigureStaticFileOptions>();
}
}
looks like AI thinks this is the correct place to start..
Path
Type
Served by
/css/site.css
Static asset
StaticFileOptions / wwwroot
/scripts/app.js
Static asset
StaticFileOptions / wwwroot
/media/1234/doc.pdf
Media asset
Umbraco media pipeline via StaticFileOptions
/media/1234/image.jpg
Media asset
ImageSharp (images only)
Both actually go through StaticFileOptions — which is why the IConfigureOptions<StaticFileOptions> approach works for both. The key difference is that for images specifically, ImageSharp intercepts before static files middleware kicks in, which is why you need the backoffice path guard.
could also use var mediaService = scope.ServiceProvider.GetRequiredService<IMediaService>(); var media = mediaService.GetMediaByPath(path);
but hits the DB, so you’d probably want to cache…
if you wanted to dymically override from media node property, or parentfolder…
Thank you Mike, this looks great. The solution I have found is this, but I am hesitant to deploy it, don’t know what negative effects it might have. What do you think?
Think it’s doing the same but in middleware, rather than hooking into the staticfileoptions that umbraco exposes and you’ve got magic strings (header names)
You might have to watch where in the pipeline it sits incase umbraco overrides etc…