You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 12:25:00