31

I'm using the OutputCache on my webuser control (.ascx)

<%@ OutputCache Duration="1000" VaryByParam="none" %>

I would like to retain the cache for next 1000 seconds, but when a specific page on my site is loaded, I would like to remove/flush/refresh the cache. Like, I want to clear the cache when MyPage.aspx is loaded. Can i flush the cache programmetically?

Its only one page being cache so there are no paramatrized versions to flush cache with.

Thanks for your help in advance.

Oleks
  • 31,955
  • 11
  • 77
  • 132

7 Answers7

34

You can use the VaryByCustom parameter for this.

In your user control you would have the following:

<%@ OutputCache Duration="1000" VaryByParam="None" VaryByCustom="MyKey" %>

Then you would override the GetVaryByCustomString method in your Global.asax like so:

public override string GetVaryByCustomString(HttpContext context, string arg)
{
    if (arg == "MyKey")
    {
        object o = context.Current.Application["MyGuid"];
        if (o == null)
        {
            o = Guid.NewGuid();
            context.Current.Application["MyGuid"] = o;
        }
        return o.ToString();
    }
    return base.GetVaryByCustomString(context, arg);
}

Finally in MyPage.aspx you would do this:

Application["MyGuid"] = Guid.NewGuid();

How does this work?

Whenever your control is cached, it is associated with a string (the string returned from the GetVaryByCustomString method when your control's VaryByCustom key is passed into it).

Whenever the control is subsequently used, GetVaryByCustomString is called again. If the returned string matches a cached version of the control, then the cached version is used.

In our case, "MyKey" is passed into GetVaryByCustomString and it returns whatever is stored in Application["MyGuid"].

Whenever MyPage.aspx is called, it changes Application["MyGuid"] to a new random value.

When your control is next used the GetVaryByCustomString method will return the new value, and because there is no cached version of the control associated with that value, the control will be regenerated. (The control will then be cached and associated with the new value, to persist until the next call to MyPage.aspx etc)

There's an overview here.

LukeH
  • 263,068
  • 57
  • 365
  • 409
  • Does it remove the previous copy or does it keep 2? – TheGateKeeper Nov 20 '12 at 17:44
  • 1
    This doesn't actually clear anything from the cache, just adds a new unique key giving the appearance of a clear cache, so yes there would now be two copies of the cached data in memory. If you are already using VaryByCustom elsewhere on the site you would probably need to amend the above code to append the GUID to the existing VaryByCustom strings. – Tim Booker Feb 17 '14 at 10:35
  • This method working successfuly. Thanks for this tip. Good works man. – Sedat Kumcu Nov 28 '17 at 10:00
11

You can use HttpResponse.RemoveOutputCacheItem or HttpResponse.AddCacheItemDependency to invalidate output cache entries.

Josef Pfleger
  • 74,165
  • 16
  • 97
  • 99
  • I ended up doing something similar: http://stackoverflow.com/questions/11585/clearing-page-cache-in-asp-net/2876701#2876701 – Kevin May 20 '10 at 18:27
  • 2
    If your OutputCacheProvider is not the default (ex. you're using AppFabric or MemCached) these methods won't work. Just a heads up for anyone considering their options... I think the VaryByCustom answer is preferable because it will work in either case. – Tom Lianza Jun 15 '11 at 07:06
  • Really both are preferable; VaryByCustom gets you some of what he's asking about, but if the previous version of the page is really dead forever, never to be used again, you'll likely reduce cache pressure by explicitly evicting it with RemoveOutputCacheItem. – Chris Moschini Mar 06 '14 at 07:55
9

It's a bit of a sledgehammer to crack a nut sort of approach but it was the simplest and most effective way to completely clear/flush the cache of an application that I found find.

Simply call:

HttpRuntime.UnloadAppDomain();

This has the same impact as recycling the app pool. Not suitable in every situation but it will definitely get the job done.

Tom Styles
  • 1,098
  • 9
  • 20
  • I agree. After exhausting many different techniques, this is the only reliable working one. – Valamas Apr 19 '16 at 01:18
  • This is not the only reliable approach to clearing the cache at all. That implies none of the other mechanisms work, which is bold. Unloading the app domain is pretty heavy-handed. –  Apr 19 '17 at 08:21
5

By taking inspiration on other post, the following snippet removes successfully every page cached by OutputCache in asp.net by using reflection:

        public static void ClearOutputCache()
        {

            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);
                    }
                }
            }
            foreach (string key in outputCacheEntries)
            {  
                HttpResponse.RemoveOutputCacheItem(key);
            }
        }
ʞᴉɯ
  • 5,376
  • 7
  • 52
  • 89
  • 1
    This answer helped me tremendously. Being able to loop through the cache and grab the keys showed me exactly what I needed. Thanks. – Scott Duffy Sep 28 '15 at 15:05
  • 2
    I tried to use the code but I get a runtime error System.NullReferenceException: var cacheEntries = cachesInfo.GetValue(cache); – Dallas Oct 31 '16 at 14:42
4

Sinсe this answer no longer works, and this answer only clears custom cache items (not the pages/MVC-actions stored in cache), I digged through ASP.NET reference source codes and came up with this:

public static void ClearAllCache()
{
    var runtimeType = typeof(System.Web.Caching.Cache);

    var ci = runtimeType.GetProperty(
       "InternalCache",
       BindingFlags.Instance | BindingFlags.NonPublic);

    var cache = ci.GetValue(HttpRuntime.Cache) as System.Web.Caching.CacheStoreProvider;
    enumerator = cache.GetEnumerator();
    while (enumerator.MoveNext())
    {
        keys.Add(enumerator.Key.ToString());
    }
    foreach (string key in keys)
    {
        cache.Remove(key);
    }
}

More info in my blog post here

Alex from Jitbit
  • 53,710
  • 19
  • 160
  • 149
4

Edit: If you have enabled kernel caching on II6+ then you will need to go with Luke's advice and use a VaryByCustom header, as clearing ASP.NET cache will not affect kernel cache.

OutputCache is stored in the ASP.NET Cache, so you can just call Cache.Remove:

List<string> keys = new List<string>();

foreach(string key in HttpRuntime.Cache)
{
    keys.Add(key);
}

foreach(string key in keys)
{
    Cache.Remove(key);
}

This will, however, remove ALL cache entries, including custom entries added by your code.

Richard Szalay
  • 83,269
  • 19
  • 178
  • 237
  • 4
    Are you sure this is the same cache? I thought that the OutputCache was a IIS thing. I don't think this works. – H H Feb 19 '09 at 14:25
  • 1
    Kernel caching is on by default in IIS7: http://technet.microsoft.com/en-us/library/cc731903(v=ws.10).aspx So if you never configured this, you have it enabled. – Chris Moschini Apr 25 '13 at 22:59
  • this will only remove custom cached items, not cached urls/pages. – Alex from Jitbit May 02 '19 at 19:49
2

you can add HttpResponse.RemoveOutputCacheItem("/YourCachePageName.aspx"); line of code in the page load event of the page, loading of which you expect the cached page's cache to go off.

suranga
  • 21
  • 1