Most Efficient Way Of Clearing Cache Using ASP.NET

I am building an ASP.NET/Umbraco powered website which is very custom data driven via entity framework, we are having to cache quite a lot of the data queries (For example searches by keyword) as it's a busy site.

But when a user creates a new data entry, I need to clear all the cached queries (Searches etc..) so the new entry is available in the results.

So in my create, delete and update methods I am calling the following method:

public static void ClearCacheItems()
{
    var enumerator = HttpContext.Current.Cache.GetEnumerator();

    while (enumerator.MoveNext())
    {
        HttpContext.Current.Cache.Remove(enumerator.Key.ToString());
    }
}

Is this really bad? I can't see how else I am supposed to clear the cached items?


The method you use is actually the correct way to clear your cache, there is just one minor 'error' in your code. The enumerator only is valid as long as the original collection remains unchanged . So while the code might work most of the time, there might be small errors in certain situations. Best is to use the following code, which does essentially the same, but does not use the enumerator directly.

List<string> keys = new List<string>();
IDictionaryEnumerator enumerator = Cache.GetEnumerator();

while (enumerator.MoveNext())
  keys.Add(enumerator.Key.ToString());

for (int i = 0; i < keys.Count; i++)
  Cache.Remove(keys[i]);

Clearing the whole ASP.NET cache for just one specific functional domain seems a bit overkill.

You could create an intermediate object, and store all your cached queries in there. This object could be just a wrapper on a dictionary object. All queries should use this object instead of playing with the ASP.NET cache directly.

Then you add this object to the ASP.NET Cache when you need it. When you need to clear the queries, just get to this object and clear the underlying dictionary. Here is a sample implentation:

    public sealed class IntermediateCache<T>
    {
        private Dictionary<string, T> _dictionary = new Dictionary<string, T>();

        private IntermediateCache()
        {
        }

        public static IntermediateCache<T> Current
        {
            get
            {
                string key = "IntermediateCache|" + typeof(T).FullName;
                IntermediateCache<T> current = HttpContext.Current.Cache[key] as IntermediateCache<T>;
                if (current == null)
                {
                    current = new IntermediateCache<T>();
                    HttpContext.Current.Cache[key] = current;
                }
                return current;
            }
        }

        public T Get(string key, T defaultValue)
        {
            if (key == null)
                throw new ArgumentNullException("key");

            T value;
            if (_dictionary.TryGetValue(key, out value))
                return value;

            return defaultValue;
        }

        public void Set(string key, T value)
        {
            if (key == null)
                throw new ArgumentNullException("key");

            _dictionary[key] = value;
        }

        public void Clear()
        {
            _dictionary.Clear();
        }
    }

If my query is represented like this:

    public class MyQueryObject
    {
       ....
    }

Then, I would use the "regional" cache like this:

// put something in this intermediate cache
IntermediateCache<MyQueryObject>.Current.Set("myKey", myObj);

// clear this cache
IntermediateCache<MyQueryObject>.Current.Clear();

It would have been very easy for the designers of the Cache class to add a Clear method to it. But they have not and it was by design - hence your code is bad .

One problem is threading implications of enumerating through a collection if the collection is modified. That would throw an error.

You really should never need to clear the whole of the cache. If server needs memory, it will clear it. Cache access is by key (for a reason) hence you need to know what you are trying to access. So if you need to remove and item, do it by a key.

UPDATE

My advice would be to design the cache in a way that clearing the cache would be very easy. For example group your cache items (create a class to hold related cache results) by an ID and use the ID as the key. Whenever something related to that ID is changed, clear the cache for that ID. Easy, peasy.

链接地址: http://www.djcxy.com/p/60568.html

上一篇: 在清除memcached中的缓存时保留会话

下一篇: 使用ASP.NET清除缓存的最有效方法