MVC Cache VaryByHeader,也需要通过标头删除缓存

时间:2015-03-25 23:28:34

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

我正在开发一个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),看来它应该尝试创建自定义密钥。所以我应该能够删除OutOutputCache(“/”),它应该为我创建自定义键,但是这似乎也没有按预期工作,它似乎仍然清除所有键。

3 个答案:

答案 0 :(得分:0)

您可以尝试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);
            }

答案 1 :(得分:0)

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

也许如果我更多地挖掘密钥生成,也许我可以编写一个密钥生成方法,但我已经走了一条不同的路线。这只是为了让其他人回答我的问题。

同样,我只想改变标题,没有参数,并且只能使一个缓存项无效。

答案 2 :(得分:0)

我参加派对有点晚了,但我有完全相同的需求,最后受到这个问题答案的启发: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());
}