AspNetCache

Mar 23, 2014 at 9:04 PM
Edited Mar 24, 2014 at 7:38 AM
Here's a small example of an AspNetCache version of ICache. I have tried to call HttpContext.Current.Cache.Remove as few times as possible (no Remove() on duplicate key entries in different entity sets) as I'm guessing it involves locking internally.
I guess, ideally, one would not use the ASP Cache as it probably involves locking. Rather, implement an identical version of the ASP Cache that is not thread-safe, and handle locking yourself to avoid locking twice (ASP's internal locking and locking _entitySetToKey) for every get/set.

Warning: The DefaultCachingPolicy settings are not respected by the code!
public class AspNetCache : ICache
{
    private readonly Dictionary<string, HashSet<string>> _entitySetToKey = new Dictionary<string, HashSet<string>>();

    public bool GetItem(string key, out object value)
    {
        lock (_entitySetToKey)
        {
            return (value = HttpContext.Current.Cache[key]) != null;
        }
    }

    public void PutItem(string key, object value, IEnumerable<string> dependentEntitySets, TimeSpan slidingExpiration, DateTimeOffset absoluteExpiration)
    {
        lock (_entitySetToKey)
        {
            HttpContext.Current.Cache.Add(key, value, null, Cache.NoAbsoluteExpiration, new TimeSpan(1, 0, 0), CacheItemPriority.Normal, null);

            foreach (var s in dependentEntitySets)
            {
                HashSet<string> keys;

                if (!_entitySetToKey.TryGetValue(s, out keys))
                    _entitySetToKey[s] = keys = new HashSet<string>();

                keys.Add(key);
            }
        }
    }

    public void InvalidateSets(IEnumerable<string> entitySets)
    {
        var keys = new HashSet<string>();

        lock (_entitySetToKey)
        {
            foreach (var s in entitySets)
            {
                HashSet<string> value;

                if (_entitySetToKey.TryGetValue(s, out value))
                {
                    foreach (var v in value)
                        keys.Add(v);
                }
            }

            foreach (var k in keys)
                HttpContext.Current.Cache.Remove(k);

            foreach (var s in entitySets)
                _entitySetToKey.Remove(s);
        }
    }

    public void InvalidateItem(string key)
    {
        lock (_entitySetToKey)
        {
            foreach (var p in _entitySetToKey)
                p.Value.Remove(key);

            HttpContext.Current.Cache.Remove(key);
        }
    }
}
Mar 26, 2014 at 6:26 AM
Thanks for posting!