【问题标题】:MVC Cache VaryByHeader, need to remove cache by header alsoMVC Cache VaryByHeader,也需要按头删除缓存
【发布时间】:2015-03-25 23:28:34
【问题描述】:

我有一个正在开发的 MVC 站点,它是多租户应用程序。我已将缓存设置为 varybyheader="host"。现在我想仅通过主机名使缓存无效。

RemoveOutputCacheItem 只接受绝对虚拟路径,不允许自定义主机名(存在非虚拟路径)。

关于如何实现这一点的任何帮助?

谢谢。

更新

这是获取内部缓存键的方法

                    var runtimeType = typeof(HttpRuntime);
                    var ci = runtimeType.GetProperty(
                       "CacheInternal",
                       BindingFlags.NonPublic | BindingFlags.Static);

                    var cache = ci.GetValue(ci, new object[0]);

                    var cachesInfo = cache.GetType().GetField(
                        "_caches",
                        BindingFlags.NonPublic | BindingFlags.Instance);
                    var cacheEntries = cachesInfo.GetValue(cache);

                    var outputCacheEntries = new List<object>();

                    foreach (Object singleCache in cacheEntries as Array)
                    {
                        var singleCacheInfo =
                        singleCache.GetType().GetField("_entries",
                           BindingFlags.NonPublic | BindingFlags.Instance);
                        var entries = singleCacheInfo.GetValue(singleCache);

                        foreach (DictionaryEntry cacheEntry in entries as Hashtable)
                        {
                            var cacheEntryInfo = cacheEntry.Value.GetType().GetField("_value",
                               BindingFlags.NonPublic | BindingFlags.Instance);
                            var value = cacheEntryInfo.GetValue(cacheEntry.Value);
                            if (value.GetType().Name == "CachedRawResponse")
                            {
                                var key = (string)cacheEntry.Value.GetType().BaseType.GetField("_key", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(cacheEntry.Value);
                                key = key.Substring(key.IndexOf("/"));
                                outputCacheEntries.Add(key);
                            }
                        }
                    }

                    var keys = new StringBuilder();

                    foreach (string key in outputCacheEntries)
                    {
                        if (key.Contains(Request.Url.Host))
                        {
                            keys.Append(key + " ");
                            HttpResponse.RemoveOutputCacheItem(key);
                        }
                    }

RemoveOutputCacheItem 不适用于此键。
他们的密钥是这样生成的:/HQNnoneV+n+FCNhostVHOSTNAME.comDE 即使是直接调用 RemoveOutputCache("/HOSTNAME.com") 也不起作用(因自定义而异)。

更新 #2

所以通读参考源代码 (http://referencesource.microsoft.com/#System.Web/HttpResponse.cs,3222f830c91ccb06),它似乎应该尝试创建自定义密钥。所以我应该能够 RemoveOutputCache("/") 并且它应该为我创建自定义键,但这似乎也没有按预期工作,它似乎仍然清除了所有键。

【问题讨论】:

    标签: c# asp.net-mvc model-view-controller


    【解决方案1】:

    你可以试试VaryByCustom

    [OutputCache(Duration = 3600, VaryByCustom = "hostname")]
    

    并定义 VaryByCustom 之类的:

        public override string GetVaryByCustomString(HttpContext Context, string Custom)
                {
    
                    //Here you set any cache invalidation policy
    
                    if (Custom == "hostname")
                    {
                        return Context.Request.Url.Host;
                    }
    
                    return base.GetVaryByCustomString(Context, Custom);
                }
    

    【讨论】:

    • 这仍然不起作用。我不想使所有缓存的项目无效,只是与主机匹配的项目。缓存是内部缓存,需要虚拟路径才能访问。对我来说奇怪的是,我可以通过反射找到所有内部缓存键并尝试通过该键删除,但这似乎也不起作用。
    【解决方案2】:

    答案是不能以这种方式完成。深入挖掘生成密钥的 RemoveOutputCache 的实际代码不会传入 varyby 参数,因此我无法获得所需的特定密钥。

    如果我对密钥生成进行深入研究,也许我可以编写一个密钥生成方法,但我走的是另一条路。这只是为了让其他人回答我的问题。

    再次,我只想根据标头进行更改,没有参数,并且能够仅使一个缓存项无效。

    【讨论】:

      【解决方案3】:

      我参加聚会有点晚了,但我有完全相同的需求,最终受到这个 SO 问题的答案的启发:Clearing Page Cache in ASP.NET

      我设置了以下测试,并且能够成功清除每个主机的缓存而无需额外的代码...

      [OutputCache(VaryByHeader = "host", Duration = 600, Location = OutputCacheLocation.Server)]
      public ActionResult TestPage()
      {
          var key = GetCacheKey("TestPage");
      
          HttpContext.Cache[key] = new object();
          Response.AddCacheItemDependency(key);
      
          return Content(DateTime.Now.ToString());
      }
      
      public ActionResult TestClearCache()
      {
          var key = GetCacheKey("TestPage");
          HttpContext.Cache.Remove(key);
          return Content("Cache cleared");
      }
      
      private string GetCacheKey(string page)
      {
          return string.Concat(page, Request.Url.Host.ToLower());
      }
      

      【讨论】:

        猜你喜欢
        • 2019-09-29
        • 1970-01-01
        • 2011-04-14
        • 2014-07-04
        • 1970-01-01
        • 2021-08-11
        • 2016-07-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多