5

I have a webpage which caches some querystring values for 30 seconds so that it does not receive duplicate values. I am using the following class:

public class MyCache   {

private static ObjectCache cache = MemoryCache.Default;

public MyCache() { }


public void Insert(string key, string value)
{

    CacheItemPolicy policy = new CacheItemPolicy();
    policy.Priority = CacheItemPriority.Default;
    policy.SlidingExpiration = new TimeSpan(0, 0, 30);
    policy.RemovedCallback = new CacheEntryRemovedCallback(this.Cacheremovedcallback);

    cache.Set(key, value, policy);
}

public bool Exists(string key)
{
    return cache.Contains(key);
}

public void Remove(string key)
{
    cache.Remove(key);
}

private void Cacheremovedcallback(CacheEntryRemovedArguments arguments)
{      
    FileLog.LogToFile("Cache item removed. Reason: " + arguments.RemovedReason.ToString() +  "; Item: [" +  arguments.CacheItem.Key + ", " + arguments.CacheItem.Value.ToString() + "]");         
}
 }

This has worked fine for a couple of weeks then suddenly the cache doesn't keep the values anymore. The CacheRemoved callback fires instantly after an item is inserted into cache and i get the removed reason: CacheSpecificEviction This is running on a Windows Server 2008 SP1, IIS7.5 with .NET 4.0. No changes were applied to the OS or IIS during this time.

Is there a way to solve this and if not, is there a better cache solution to use in a web page ?

Thank you in advance.

wanglyih
  • 51
  • 1
  • 2

3 Answers3

1

Looking at the source code of MemoryCacheStore (that should be the default store used by MemoryCache.Default) it seems that the remove callback with argument CacheSpecificEviction is only called when the cache is disposed:

https://referencesource.microsoft.com/#System.Runtime.Caching/System/Caching/MemoryCacheStore.cs,230

Look around and make sure your cache object is not being disposed accidentally.

Alberto
  • 15,626
  • 9
  • 43
  • 56
0

I also found out that the RemovedCallback executes if you call MemoryCache.Set on an existing item - because .Set overwrites the item in cache.

The workaround is to use .Add instead of .Set

Even though the OP mentions CacheSpecificEviction and this that does not answer his question, but just in case someone is facing a similar problem and landed on this question after searching the Web.

Alex from Jitbit
  • 53,710
  • 19
  • 160
  • 149
-1

Try this one:

policy.AbsoluteExpiration = DateTime.Now.AddSeconds(30);

Thats how I use Cache:

public static class CacheHelper
{
    private static ObjectCache _cache;
    private const Double ChacheExpirationInMinutes = 10;

    /// <summary>
    /// Insert value into the cache using
    /// appropriate name/value pairs
    /// </summary>
    /// <typeparam name="T">Type of cached item</typeparam>
    /// <param name="entity">item cached</param>
    /// <param name="key">Name of item</param>
    public static void Add<T>(T entity, string key) where T : class
    {
        if (_cache == null)
        {
            _cache = MemoryCache.Default;
        }
        if (_cache.Contains(key))
            _cache.Remove(key);
        CacheItemPolicy cacheItemPolicy = new CacheItemPolicy();
        cacheItemPolicy.AbsoluteExpiration = DateTime.Now.AddMinutes(ChacheExpirationInMinutes);
        _cache.Set(key, entity, cacheItemPolicy);
    }

    /// <summary>
    /// Remove item from cache
    /// </summary>
    /// <param name="key">Name of cached item</param>
    public static void Clear(string key)
    {
        if (_cache == null)
        {
            _cache = MemoryCache.Default;
            return;
        }
        _cache.Remove(key);
    }

    /// <summary>
    /// Retrieve cached item
    /// </summary>
    /// <typeparam name="T">Type of cached item</typeparam>
    /// <param name="key">Name of cached item</param>
    /// <returns>Cached item as type</returns>
    public static T Get<T>(string key) where T : class
    {
        if (_cache == null)
        {
            _cache = MemoryCache.Default;
        }
        try
        {
            return (T)_cache.Get(key);
        }
        catch
        {
            return null;
        }
    }
}
Maris
  • 4,608
  • 6
  • 39
  • 68
  • Not sure how this solves the issue. As they said, it works for a while then stops working. – Daniel Kelley Feb 15 '13 at 10:46
  • Actually you are right. Dont think that it will solve the isue. But this class works for me very well even for massive project with a lot of users. – Maris Feb 15 '13 at 10:48
  • I have one idea. Maybe you try to save to your cache object with large relation chain. Something Like User--> NxCategories-->N*MxProducts-->N*M*FxParametrs. What are you holding in your cache? – Maris Feb 15 '13 at 10:51
  • Thank you for your answers. The class provided has the same behaviour as mine. I believe the problem is somewhere in IIS. As i said, i am using it in a web page. An ID received by the webpage via querystring is cached as string. I just query the cache in Page_Load method and if the value is not there, i insert it. – wanglyih Feb 15 '13 at 12:23