CacheItemPolicy - SlidingExpiration "Accessed" rules? - c#

From http://msdn.microsoft.com/en-us/library/system.runtime.caching.cacheitempolicy.slidingexpiration(v=vs.110).aspx ...
"A span of time within which a cache entry must be accessed before the cache entry is evicted from the cache. The default is NoSlidingExpiration, meaning that the item should not be expired based on a time span."
What exactly is 'accessed' ? Does that mean if I hit the cached item like:
var object = cache["cachekeyname"];
It's considered to be 'accessed' ?
Or would it only be considered accessed if I actually modify the cached item?

it does mean that the cache is accessed if the following code is called:
var object = cache["cachekeyname"];
Therefore if the piece of code or functionality containing the above code snippet is not called within X time since you put the object into the cache or it was last accessed it will be removed from the cache.

Related

How to attach a listener to MemoryCache which gets called on expiration of keys?

I am using MemoryCache in one of my project to cache some keys and value.
private bool CacheEntries<T>(MemoryCache memoryCache, string cacheKey, T value, Configuration config, Action<MemoryCacheEntryOptions> otherOptions = null)
{
int minutes = randomGenerator.Next(config.LowTime, config.HighTime);
MemoryCacheEntryOptions options = new MemoryCacheEntryOptions()
{
Size = config.Size,
Priority = config.Priority,
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(minutes)
};
if (otherOptions != null) otherOptions(options);
CacheKeys.Add(cacheKey);
memoryCache.Set<T>(cacheKey, value, options);
return true;
}
I have an expiration on my keys as shown above. Also I am storing same key in CacheKeys HashSet data structure for later use. Is there any way to attach a listener on my MemoryCache that whenever it is expiring any items then that listener should get called so that I can remove those keys from CacheKeys HashSet as well. Basically I want to be consistent with what I have in CacheKeys and MemoryCache.
Is this possible to do?
You appear to be using the Platform Extensions object from Microsoft.Extensions.Caching.Memory. You can use the MemoryCacheEntryOptions.PostEvictionCallbacks property for the MemoryCacheEntryOptions object when you set the item's value in the cache:
Gets or sets the callbacks will be fired after the cache entry is evicted from the cache.
Alternatively, if you can change to the System.Runtime.Caching version of MemoryCache, you can use the CacheItemPolicy when setting the value. From the documentation:
A CacheItemPolicy instance contains information that can be associated with a cache entry. For example, when a cache entry is about to be removed from the cache, a CacheEntryUpdateArguments object is passed to a callback method. The UpdatedCacheItemPolicy property of the CacheEntryUpdateArguments object can pass a reference to a CacheItemPolicy instance that can include eviction and expiration details about the cache entry.
Another alternative with that version of MemoryCache is to call CreateCacheEntryChangeMonitor:
The CreateCacheEntryChangeMonitor method creates a CacheEntryChangeMonitor instance. This specialized change monitor is used to monitor the cache entries that are specified in the keys collection and to trigger events when the entries change.
A monitored entry is considered to have changed for any of the following reasons:
The key does not exist at the time of the call to the CreateCacheEntryChangeMonitor method. In that case, the resulting CacheEntryChangeMonitor instance is immediately set to a changed state. This means that when code subsequently binds a change-notification callback, the callback is triggered immediately.
The associated cache entry was removed from the cache. This can occur if the entry is explicitly removed, if it expires, or if it is evicted to recover memory

Inquiry about Kentico9 Caching

I'm using Kentico 9 and trying to test caching. I would like to ask about how to replace the existing cache if a new value is entered.
Recently was trying to cache with this code:
CacheHelper.Cache(cs => getCachingValue(cs, cacheValue), new CacheSettings(10, "cacheValue"));
public string getCachingValue(CacheSettings cs, string result) {
string cacheValue= result;
if (cs.Cached)
{
cs.CacheDependency = CacheHelper.GetCacheDependency("cacheValue");
}
return cacheValue;
}
When caching data you need to setup correct cache dependencies. For example this is cache dependency for all users:
if (cs.Cached)
{
cs.CacheDependency = CacheHelper.GetCacheDependency("cms.user|all");
}
This will drop cache whenever user has been updated or created. So next time you call the method it will get data from database and cache it again until cache expires or someone adds/updates user.
So you don't need to take care about replacing/updating cached data - appropriate mechanism is already there.
See cache dependencies in documentation.
Since your cache dependency is called "cacheValue", you need to "touch" that particular cache key, to force the cache to clear.
When the value you are caching changes (the value you provide to the string result parameter of the getCachingValue method), call the CacheHelper.TouchKey method to force the cache to clear:
CacheHelper.TouchKey("cacheValue");
(You should also consider changing the name of the cache key, to prevent confusion)
Keep in mind, that if your cache key is "cacheValue" then any call that is made to this will always be the same 'hit.' The CacheSetting key is it's 'unique identifier' you could say, and the Cache Depenency is how it automatically resets.
So for example, say you cache a function that adds two values (wouldn't really need to cache this, but for an example where the input changes)
If you have a cache value for your "AddTwoValues(int a, int b)" of
CacheHelper.Cache(cs => AddTwoValuesHelper(cs, a, b), new CacheSettings(10, "cacheValue"));
The first call will cache the the value of the call (say you pass it 1 and 2), so it caches "3" for the key "cacheValue"
Second call if you pass it 3, 5, the cache key is still "cacheValue" so it will assume it's the same call as the first and return 3, and not even try to add 3+5.
I usually append any parameters to the cache key.
CacheHelper.Cache(cs => AddTwoValuesHelper(cs, a, b), new CacheSettings(10, string.Format("AddTwoValues|{0}|{1}", a, b)));
This way if i call it with 1 and 2, twice, the first it will processes and cache "3" for the key "AddTwoValues|1|2", and when called again the key will match so it will just return the cached value.
If you call with different parameters, then the cache key will be different.
Make sense?
The other answers of course talk on the cache dependency in the helper function:
if (cs.Cached)
{
cs.CacheDependency = CacheHelper.GetCacheDependency("cms.user|all");
}
Which identify how it automatically clears (if you do cms.users|all as the dependency, whenever a user is changed, this cache automatically clears itself)

Webservice Method generic list fill and keep for 1 day

I have a webmethod inside a webservice that calls another webservice to get data and fills a generic list then it returns it, what i want to do is to save the list in memory, so the next time the webmethod is invoked it does not hit the other webservice but just returns the list, i have tried but when i invoke the web method for the second time the list count shows as 0, looks like garbage collection is cleaning all. any suggestions ?
Store it in the ASP.NET cache. Setting an absolute expiration of midnight should assure that you only get it once per day (unless it gets tossed from the cache due to space issues).
[Web Method]
public List<Foo> GetFoos()
{
var foos = Cache["FooList"] as List<Foo>;
if (foos == null)
{
... get foos from remote web service ...
var expiration = DateTime.Today.AddHours(7);
if (DateTime.Now >= expiration)
{
expiration = expiration.AddDays(1);
}
Cache.Insert( "FooList", foos, null, expiration, Cache.NoSlidingExpiration );
}
return foos;
}
Note: you could also use output caching as well, but you're limited to a sliding expiration. That is, it will be cached for a duration based on when the request occurs. It's not clear that's what you want. For example, what if the first request occurs at 11pm with a 24 hour duration, you wouldn't check again until 11pm the next day. If you have data changing on a daily basis, you're better off using the ASP.NET cache in conjunction with output caching on a shorter duration to ensure that you get the latest, daily data in a timely fashion.
Updated example based on comments.
It sounds to me like your list might either not be static, or it might constantly be new'd within a non-static constructor. There are three possible fixes for this:
Make sure that your generic list is a static property which only get initialised within a static constructor.
Seeing your time requirements I would also suggest potentially looking into MemoryCache or Cache.
Use the WebMethod attribute and set a CacheDuration (i.e: [WebMethod(CacheDuration=86400)])
I have not tried this on a webservice, but I think output cashing would work.
[WebMethod(CacheDuration=86400)]
public string FunctionName(string Name)
{
...code...
return(sb.ToString());
}
Read: How to perform output caching with Web services in Visual C# .NET

How do the caching 'Priority' and 'AbsoluteExpiration' work together?

I found myself into a CacheItem that didn't clean up correctly. While looking at MSDN and correct myself into using Utc-based calculation, I found this confusing information:
CacheItemPolicy.Priority
CacheItemPolicy.AbsoluteExpiration
AbsolutExpiration is used to set a "keep-alive" of a CacheItem, Priority.NotRemovable is used to force CacheItem to exist forever. No notification about what property overrides the other.
The code below do compile and SQL Profiler also confirm that the database is queried only once, while every other request came from cache.
CacheItemPolicy _cachePolicy = new CacheItemPolicy()
{
AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddHours(6)),
Priority = CacheItemPriority.NotRemovable
};
I assume that this code force the cache items to stay forever but are cleared after 12 hours from creation, in line with the MSDN's note about the setting.
"Cache implementations should set the NotRemovable priority for a
cache entry only if the cache implementation provides ways to evict
entries from the cache and to manage the number of cache entries"
Then the other side, why would both properties work together at all? Does the implementation bring some kind of "more non-removable"?
So according to this "NotRemovable" prevents the cache entry from being removed automatically (like when the cache is running out of space) but will be removed when it expires or you manually take it out of the cache.
NotRemovable The cache items with this priority level will not be automatically deleted from the cache as the server frees system memory. However, items with this priority level are removed along with other items according to the item's absolute or sliding expiration time.

C# Collection whose items expire

I am writing a Console Application in C# in which I want to cache certain items for a predefined time (let's say 1 hour). I want items that have been added into this cache to be automatically removed after they expire. Is there a built-in data structure that I can use? Remember this is a Console App not a web app.
Do you actually need them removed from the cache at that time? Or just that future requests to the cache for that item should return null after a given time?
To do the former, you would need some sort of background thread that was periodically purging the cache. This would only be needed if you were worried about memory consumption or something. If you just want the data to expire, that would be easy to do.
It is trivial to create such a class.
class CachedObject<TValue>
{
DateTime Date{get;set;}
TimeSpan Duration{get;set;}
TValue Cached{get;set;}
}
class Cache : Dictionary<TKey,TValue>
{
public new TValue this(TKey key)
{
get{
if (ContainsKey(key))
{
var val = base.this[key];
//compare dates
//if expired, remove from cache, return null
//else return the cached item.
}
}
set{//create new CachedObject, set date and timespan, set value, add to dictionary}
}
Its already in the BCL. Its just not where you expect to find it: You can use System.Web.Caching from other kinds of applications too, not only in ASP.NET.
This search on google links to several resources about this.
I don't know of any objects in the BCL which do this, but I have written similar things before.
You can do this fairly easily by just including a System.Threading.Timer inside of your caching class (no web/winforms dependencies), and storing an expiration (or last used) time on your objects. Just have the timer check every few minutes, and remove the objects you want to expire.
However, be watchful of events on your objects. I had a system like this, and was not being very careful to unsubscribe from events on my objects in the cache, which was preventing a subtle, but nasty memeory leak over time. This can be very tricky to debug.
Include an ExpirationDate property in the object that you will be caching (probably a wrapper around your real object) and set it to expire in an hour in its constructor. Instead of removing items from the collection, access the collection through a method that filters out the expired items. Or create a custom collection that does this automatically. If you need to actually remove items from the cache, your custom collection could instead purge expired items on every call to one of its members.

Categories