Caching for Non-Web Applications – Part 2

In my last blog post, entitled Caching for Non-Web Applications – Part 1 I introduced you to the MemoryCache class. This class allows you to create a cache for any type of application just like in ASP.NET applications. The great thing about the MemoryCache class is there is no reliance on the System.Web namespace. This means you are free to use the MemoryCache class in any type of application such as Windows Forms, WPF and Windows Services. The last blog post showed you how to add and retrieve data from the cache. This blog post expands on the last one and shows you additional methods you can take advantage of to work with cache data.

Add or Get Existing

The AddOrGetExisting method has the same signature as the Add method. However, instead of returning a true or false value, it will either return a null if the key/value pair was added to the cache, or returns the object if the key value is found already in the cache.

object ret;
ret = MemoryCache.Default.AddOrGetExisting("Key2", 
         "Value 2", DateTimeOffset.Now.AddSeconds(5));
if (ret == null) {
MessageBox.Show("Key did NOT exist");
}
else {
MessageBox.Show("The Key did already exist");
}

AddOrGetExisting Using CachePolicy

Just like you are able to add a new item to the cache using the CachePolicy using the Add method, you can do the same with the AddOrGetExisting method. The code below will add a new cache item with a sliding expiration of 5 seconds.

object ret;
CacheItemPolicy pol = new CacheItemPolicy();
pol.SlidingExpiration = new TimeSpan(0, 0, 5);
ret = MemoryCache.Default.AddOrGetExisting("Key2", 
                   "Value 2", pol);
if (ret == null) {
MessageBox.Show("Key did NOT exist");
}
else {
MessageBox.Show("The Key did already exist");
}

Set Method

The Set method adds an entry into the cache if the specified key value does not exist. However, if the key value does exist, it will update the value for that key in the cache. I prefer to use this method over the Add or AddOrGetExisting as I typically just want to either add, or update, and not worry about whether I have created the value previously or not. This method does not return any value.

MemoryCache.Default.Set("Key3", "Value 3", 
     DateTimeOffset.Now.AddSeconds(5));

You can use a CacheItemPolicy to set a sliding expiration on the item to cache.

CacheItemPolicy pol = new CacheItemPolicy();
pol.SlidingExpiration = new TimeSpan(0, 0, 5);
MemoryCache.Default.Set("Key3", "Value 3", pol);

Notify Before Removal from Cache

Just before an item is to be removed from the cache because it is expiring, you may create a method to respond to this event. Write the following method to accept a CacheEntryUpdateArguments object. Within this method body you can write whatever code you want. In the sample below I am just writing out the Key and the reason for the removal.

private void UpdateHandler(CacheEntryUpdateArguments e) {
Console.WriteLine(e.Key);
Console.WriteLine(e.RemovedReason.ToString());
}

Once you have this method written, you assign that method to the UpdateCallback property of a CacheItemPolicy object. The code snippet below shows you how you assign this method to the UpdateCallback property.

CacheItemPolicy pol = new CacheItemPolicy();
pol.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(3);
pol.UpdateCallback = UpdateHandler;
MemoryCache.Default.Set(THE_KEY, "Update 3", pol);

If you run the above code and wait a few seconds, you will see a couple of messages printed in the Output window.

Within the UpdateHandler method you also have the option to change the value in the cache and place it back into the cache. You do this by assigning a new CacheItem object with the same key and a value to the e.UpdatedCacheItem property. You must also set the e.UpdatedCacheItemPolicy property to a new CacheItemPolicy object. When this method ends, the item is not removed and is updated within the cache. The code to do this is shown below.

private void UpdateHandler(CacheEntryUpdateArguments e) {
Console.WriteLine(e.Key);
Console.WriteLine(e.RemovedReason.ToString());
e.UpdatedCacheItem = new CacheItem(e.Key, "My New Value");
CacheItemPolicy pol = new CacheItemPolicy();
pol.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(10);
pol.UpdateCallback = UpdateHandler;
e.UpdatedCacheItemPolicy = pol;
}

Notify After Removal from Cache

If you do not care to update an item in the cache, you may just respond to the RemovedCallback event. The design pattern is similar to what you just wrote in the previous example. First create a method that accepts a CacheEntryRemovedArguments object. The only two properties in that object you care about are the e.RemovedReason and the e.CacheItem. The e.CacheItem object contains the item that was just removed from the cache.

private void RemovedHandler(CacheEntryRemovedArguments e) {
  Console.WriteLine(e.RemovedReason.ToString());
  Console.WriteLine("Removed Handler: " + e.CacheItem.Key);
}

With the RemovedHandler method created, you may now set the RemovedCallback property of a CacheItemPolicy object. You then use that CacheItemPolicy object to add a new item into the MemoryCache object.

CacheItemPolicy pol = new CacheItemPolicy();
pol.SlidingExpiration = new TimeSpan(0, 0, 3);
pol.RemovedCallback = RemovedHandler;
MemoryCache.Default.Set("Key3", "Remove 3", pol);

If you run the above code, then either let the value expire, or explicitly remove the item from cache, the RemovedHandler method is called.

Summary

In this blog post you learned to call the AddOrGetExisting method. This method is different from the Add method as it either adds an item to the cache, or retrieves one if they key already exists. You also learned to use the Set method to either add a new item to the cache, or update an item in the cache if it already exists. Providing a couple of callback functions to the CacheItemPolicy lets you respond when an item is about to be deleted from the cache, or after it has already been deleted.

Sample Code

You can download the code for this sample at www.pdsa.com/downloads. Choose the category “PDSA Blogs”, then locate the sample Caching for Non-Web Applications.

Loading