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

.NET 5中将响应缓存保存至服务器的实现方案咨询

.NET Core/.NET 5 服务器端响应缓存(OutputCache)实现方案

.NET Core 3.x / .NET 5 确实没有内置和 .NET Framework MVC 完全一致的服务器端 OutputCache 功能,你可以通过自定义过滤器 + 缓存组件的方式实现,用法可以做到和旧版 OutputCache 高度接近,步骤如下:

1. 基础依赖配置

首先引入缓存相关组件,单实例场景用内存缓存即可,分布式场景可以替换为 Redis 等分布式缓存:

  • 安装 NuGet 包:Microsoft.Extensions.Caching.Memory
  • 在 Startup.cs 中注册服务:
// 注册内存缓存服务
services.AddMemoryCache();
// 注册自定义缓存过滤器
services.AddScoped<ServerOutputCacheAttribute>();

2. 自定义缓存特性实现

直接继承 ActionFilterAttribute,模拟旧版 OutputCache 的常用参数:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ServerOutputCacheAttribute : ActionFilterAttribute
{
    // 缓存时长,单位:秒
    public int Duration { get; set; } = 60;
    // 按请求参数区分缓存,多个参数用逗号分隔,填*代表匹配所有参数
    public string VaryByParam { get; set; } = "*";
    // 按请求头区分缓存,多个头用逗号分隔
    public string VaryByHeader { get; set; } = "";

    private const string CacheKeyPrefix = "ServerOutputCache_";

    public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        var cache = context.HttpContext.RequestServices.GetRequiredService<IMemoryCache>();
        var cacheKey = BuildCacheKey(context.HttpContext);

        // 缓存命中直接返回结果
        if (cache.TryGetValue(cacheKey, out IActionResult cachedResult))
        {
            context.Result = cachedResult;
            return;
        }

        // 缓存未命中,执行接口逻辑并缓存结果
        var executedContext = await next();
        if (executedContext.Result != null && context.ModelState.IsValid)
        {
            var cacheOptions = new MemoryCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(Duration)
            };
            cache.Set(cacheKey, executedContext.Result, cacheOptions);
        }
    }

    // 生成唯一缓存Key
    private string BuildCacheKey(HttpContext context)
    {
        var keyParts = new List<string> { CacheKeyPrefix, context.Request.Path };

        // 拼接参数维度
        if (!string.IsNullOrEmpty(VaryByParam))
        {
            if (VaryByParam == "*")
            {
                keyParts.Add(context.Request.QueryString.ToString());
            }
            else
            {
                var paramNames = VaryByParam.Split(',', StringSplitOptions.RemoveEmptyEntries);
                foreach (var param in paramNames)
                {
                    var paramVal = context.Request.Query[param.Trim()].ToString();
                    keyParts.Add($"{param.Trim()}={paramVal}");
                }
            }
        }

        // 拼接请求头维度
        if (!string.IsNullOrEmpty(VaryByHeader))
        {
            var headerNames = VaryByHeader.Split(',', StringSplitOptions.RemoveEmptyEntries);
            foreach (var header in headerNames)
            {
                var headerVal = context.Request.Headers[header.Trim()].ToString();
                keyParts.Add($"{header.Trim()}={headerVal}");
            }
        }

        return string.Join("_", keyParts);
    }
}

3. 使用方法和 .NET MVC 完全一致

直接在 Controller 或者 Action 上标记特性即可:

// 缓存60秒,按所有请求参数区分缓存
[ServerOutputCache(Duration = 60, VaryByParam = "*")]
public IActionResult List(int page, string keyword)
{
    return View();
}

// 缓存300秒,仅按id参数区分缓存
[ServerOutputCache(Duration = 300, VaryByParam = "id")]
public IActionResult Detail(int id)
{
    return View();
}

补充说明

  • 如果需要缓存视图渲染后的 HTML 而非 ActionResult,可以将逻辑迁移到 ResultFilter 中,将最终响应流内容作为缓存值存储即可
  • 分布式场景下把 IMemoryCache 替换为 IDistributedCache,缓存内容做序列化处理即可适配
  • 后续如果升级到 .NET 7+ 版本,可以直接使用框架内置的 [OutputCache] 特性,原生支持服务器端缓存,用法和 .NET MVC 版本基本一致

内容的提问来源于stack exchange,提问作者Blackerback

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 22:24:07