Wednesday, February 12, 2014

Static CacheItemPolicy in .NET

An interesting riddle came today that took me some time to analyze. I was using the .NET 4 MemoryCache object to cache application entities and wanted to expire them with sliding expiration, i.e. after some time of inactivity. What I cached was dictionaries of objects. And naturally when releasing the objects held in these dictionaries some work is needed to make sure these objects are not referenced anywhere.

My first bet was using the RemovedCallback data member of the CacheItemPolicy to do the job there. Then it turned out that this is not optimal since upon expiration of the object it might happen that the object still needs to stay in the cache. The documentation suggests that UpdateCallback may be better suited here since it allows to tell the MemoryCache to keep the object. I changed the implementation and it seemed that it fits the application logic quite well.

Testing the application revealed some weird InvalidOperation exception with the message of "The method has already been invoked, and can only be invoked once." At the times that a various cache entries were added to cache.

In the end it took me quite some time to discover that the CacheItemPolicy that I was using to set the UpdateCallback was a static object. And it seems like .NET Framework internally makes use of ChangeMonitors in this case. Naturally using a static CacheItemPolicy was a very bad idea here since this object became a monster.

Adding a new CacheItemPolicy for each of the added cache items solved the problem of course.

So don't use static CacheItemPolicy. At least not if you use UpdateCallback.

1 comment:

  1. Ilya, I just ran into the same issue with MemoryCache and UpdateCallback. Your suggestion worked well - I easily created a new CacheItemPolicy every time I did MemoryCache.Set()

    ReplyDelete