ASP.NET Core MVC中输出缓存中间件不识别控制器根URL的原因?
问题原因
ASP.NET Core的输出缓存默认以完整请求路径作为缓存键的核心组成部分,/Controller/和/Controller/Index是两个完全不同的请求路径,因此会被生成两个独立的缓存条目,彼此不会共享缓存内容。
你观察到的“缓存不生效”,本质是访问/Controller/时,这个路径的缓存尚未生成(每次访问都是针对这个路径的首次请求),所以每次都会执行数据库查询;而/Controller/Index的缓存已经生成,后续访问直接命中缓存,造成了“一个生效一个不生效”的差异。
解决方案
要让这两个路径共享同一缓存,你可以通过以下几种方式处理:
1. 调整OutputCache特性的缓存维度
如果你的路由配置中Index是控制器的默认动作,可以通过VaryByRoute参数指定只按控制器维度生成缓存键,忽略动作名称的差异:
[HttpGet] [OutputCache(Duration = 43200, NoStore = false, VaryByRoute = new[] { "controller" })] public IActionResult Index() { // 你的业务代码 }
这样不管是访问/Controller/还是/Controller/Index,都会基于控制器名称生成相同的缓存键,从而共享缓存内容。
2. 自定义缓存键生成逻辑
创建自定义的缓存键生成器,将两个路径映射为同一个缓存标识:
public class CustomCacheKeyBuilder : DefaultOutputCacheKeyBuilder { public CustomCacheKeyBuilder(IOptions<OutputCacheOptions> options) : base(options) { } public override string Build(HttpContext context) { var path = context.Request.Path.Value; // 把末尾带斜杠的控制器路径替换为带Index的路径 if (path.EndsWith("/") && !path.EndsWith("/Index")) { var trimmedPath = path.TrimEnd('/'); context.Request.Path = $"{trimmedPath}/Index"; } return base.Build(context); } }
然后在Program.cs中注册这个自定义实现:
builder.Services.AddOutputCache(options => { options.KeyBuilderType = typeof(CustomCacheKeyBuilder); });
3. 统一请求路径(最直接)
在路由配置中添加重定向规则,让访问/Controller/的请求自动跳转到/Controller/Index,确保所有请求都使用同一个路径:
// 默认路由配置 app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); // 添加重定向规则 app.MapGet("/{controller}/", async context => { var controllerName = context.Request.RouteValues["controller"]?.ToString(); if (!string.IsNullOrEmpty(controllerName)) { context.Response.Redirect($"/{controllerName}/Index"); } });
这种方式从根源上统一了请求路径,自然就会共享同一缓存。
内容的提问来源于stack exchange,提问作者PatJon6
相关产品推荐
相关产品推荐

