1

I have a MVC site that I am developing that is multi-tenant application. I have set up the cache to varybyheader="host". Now I'd like to invalidate the cache only by hostname.

The RemoveOutputCacheItem only takes absolute virtual paths and isn't allowing a custom host name (there by being a non-virtual path).

Any help on how to achieve this?

Thanks.

Update

Here is how I can get the internal cache keys

                    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);
                        }
                    }

That RemoveOutputCacheItem doesn't work with this key.
They key is generated like this: /HQNnoneV+n+FCNhostVHOSTNAME.comDE Even a direct call RemoveOutputCache("/HOSTNAME.com") doesn't work either (with vary by custom).

Update #2

So read through the reference source code (http://referencesource.microsoft.com/#System.Web/HttpResponse.cs,3222f830c91ccb06) and it appears that it should attempt to create the custom key. So I should be able to RemoveOutputCache("/") and it should create the custom key for me, but this also appears to not be working as expected, it still appears to clear all keys.

KnowHowSolutions
  • 680
  • 3
  • 10

3 Answers3

0

You can try the VaryByCustom

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

And define the VaryByCustom like:

    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);
            }
JOBG
  • 4,544
  • 4
  • 26
  • 47
  • This still doesn't work. I don't want to invalidate all the cached items, just the one that matches the host. The cache is an internal cache that requires a virtual path to gain access to. What is odd to me is that I can find, with reflection, all the internal cache keys and attempt to remove by that key and that also doesn't appear to work. – KnowHowSolutions Mar 26 '15 at 17:19
0

The answer is that this cannot be done in this manner. Digging into the actual code for RemoveOutputCache where it generates the key doesn't pass in the varyby parameter and therefore I am unable to get the specific key needed.

Perhaps if I dug a bit more into the key generation, perhaps I could write a key gen method, but I've gone a different route. This is just to give everyone else an answer to my issue.

Again I only wanted to vary by header, no params and be able to invalidate just that one cached item.

KnowHowSolutions
  • 680
  • 3
  • 10
0

I'm a little late to the party, but I had the exact same need, and ended up being inspired by the answers in this SO question: Clearing Page Cache in ASP.NET

I setup the following below test, and was able to successfully clear the cache per host with no additional code...

[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());
}
Community
  • 1
  • 1
Chris Curtis
  • 1,478
  • 1
  • 10
  • 21