.NET 7:如何在控制器内部设置OutputCache过期时间?
解决方案:通过自定义输出缓存策略+控制器动态设置响应头实现动态缓存时长
核心思路是:在控制器方法内根据场景设置缓存时长的响应头,然后自定义输出缓存策略,在响应处理阶段读取该头并设置缓存过期时间。
步骤1:实现自定义输出缓存策略
创建一个实现IOutputCachePolicy的类,在ServeResponseAsync方法中读取控制器设置的响应头,动态指定缓存时长:
public class DynamicOutputCachePolicy : IOutputCachePolicy { public ValueTask CacheRequestAsync(OutputCacheContext context, CancellationToken cancellationToken) { // 仅允许GET/HEAD请求被缓存,可根据需求调整 var request = context.HttpContext.Request; context.AllowCache = HttpMethods.IsGet(request.Method) || HttpMethods.IsHead(request.Method); return ValueTask.CompletedTask; } public ValueTask ServeFromCacheAsync(OutputCacheContext context, CancellationToken cancellationToken) { // 允许从缓存读取响应 context.AllowCache = true; return ValueTask.CompletedTask; } public ValueTask ServeResponseAsync(OutputCacheContext context, CancellationToken cancellationToken) { // 读取自定义响应头中的缓存时长(单位:分钟) if (context.HttpContext.Response.Headers.TryGetValue("X-Cache-Expire-Minutes", out var expireValue) && int.TryParse(expireValue, out var minutes)) { context.ResponseExpirationTimeSpan = TimeSpan.FromMinutes(minutes); } // 备选:读取标准Cache-Control头的max-age值 var cacheControl = context.HttpContext.Response.GetTypedHeaders().CacheControl; if (cacheControl?.MaxAge != null) { context.ResponseExpirationTimeSpan = cacheControl.MaxAge.Value; } context.AllowCache = true; return ValueTask.CompletedTask; } }
步骤2:注册自定义策略
在Program.cs中添加输出缓存服务并注册自定义策略:
var builder = WebApplication.CreateBuilder(args); // 添加输出缓存并注册自定义策略 builder.Services.AddOutputCache(options => { options.AddPolicy("DynamicCache", policy => policy.WithCustomPolicy<DynamicOutputCachePolicy>()); }); builder.Services.AddControllersWithViews(); var app = builder.Build(); // 启用输出缓存中间件 app.UseOutputCache(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run();
步骤3:在控制器中动态设置缓存时长
在需要动态缓存的控制器方法中,根据业务场景设置响应头(二选一即可):
public class ProductController : Controller { [OutputCache(PolicyName = "DynamicCache")] public IActionResult List() { // 场景1:缓存2分钟 Response.Headers["X-Cache-Expire-Minutes"] = "2"; return View(GetProductList()); } [OutputCache(PolicyName = "DynamicCache")] public IActionResult Details(int id) { // 场景2:缓存10分钟 // 使用标准Cache-Control头的方式 Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue { Public = true, MaxAge = TimeSpan.FromMinutes(10) }; return View(GetProductDetails(id)); } }
为什么之前的方式无效?
CacheRequestAsync和ServeFromCacheAsync是在控制器方法执行前触发的,此时你在控制器中设置的HttpContext.Items还未写入,自然读取不到;而若在ServeResponseAsync中直接设置ResponseExpirationTimeSpan但未关联控制器的动态值,也无法生效。上述方案通过控制器先设置响应头,策略在响应阶段读取头信息的顺序,完美适配了生命周期的问题。
内容的提问来源于stack exchange,提问作者Xavier John
相关产品推荐
相关产品推荐

