Archive

Archive for the ‘MemoryCache’ Category

Using MemoryCache in .Net 4.0

November 27, 2011 2 comments

Since ASP.Net first came, it came up with a very powerful feature of in-memory object cache (System.Web.Caching.Cache) to store commonly used expensive data on server side. Almost every ASP.Net application/site uses this feature now. But it suffered from few shortcomings like-

  • It is available in ASP.Net only leaving WinForms or WPF clients puzzled.
  • It is not extensible to accommodate other demands to store cache objects in disk or Sql Server. However, MS after realizing these shortcomings, Caching Application Block library was included in its Enterprise Library.
  • .Net developers have to look for their own mechanisms to create logical in-memory partitions called regions to group or organize cache objects in memory.

However, .Net 4.0 came up with a new set of caching APIs in System.Runtime.Caching namespace that addresses all the above shortcomings. This new namespace can be found in System.Runtime.Caching.dll assembly. But this assembly reference is available only target framework of .Net Framework 4, not .Net Framework 4 Client Profile.

The System.Runtime.Caching namespace contains two core set of classes:

  • Concrete implementation of System.Runtime.Caching.MemoryCache class to support in-memory object cache. MemoryCache is closely modeled after old System.Web.Caching.Cache of ASP.Net. However, one does not have to rely upon System.Web assembly to use MemoryCache (We will see it through an example shortly).
  • Abstract types to build custom cache implementation other than in-built MemoryCache.

Now let’s move to try out an example to leverage MemoryCache features. First of all we will create a class library type project. Add a class MyCache and assembly reference of System.Runtime.caching.dll.

MyCache Code sample:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Caching;

namespace DotNetCachingWrapper
{
public enum MyCachePriority
{
Default,
NotRemovable
}

public class MyCache
{
// Gets a reference to the default MemoryCache instance.
private static ObjectCache cache = MemoryCache.Default;
private CacheItemPolicy policy = null;
private CacheEntryRemovedCallback callback = null;

public void AddToMyCache(String CacheKeyName, Object CacheItem, MyCachePriority MyCacheItemPriority, List<String> FilePath)
{
//
callback = new CacheEntryRemovedCallback(this.MyCachedItemRemovedCallback);
policy = new CacheItemPolicy();
policy.Priority = (MyCacheItemPriority == MyCachePriority.Default) ? CacheItemPriority.Default : CacheItemPriority.NotRemovable;
policy.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(10.00);
policy.RemovedCallback = callback;
policy.ChangeMonitors.Add(new HostFileChangeMonitor(FilePath));

// Add inside cache
cache.Set(CacheKeyName, CacheItem, policy);
}

public Object GetMyCachedItem(String CacheKeyName)
{
//
return cache[CacheKeyName] as Object;
}

public void RemoveMyCachedItem(String CacheKeyName)
{
//
if (cache.Contains(CacheKeyName))
{
cache.Remove(CacheKeyName);
}
}

private void MyCachedItemRemovedCallback(CacheEntryRemovedArguments arguments)
{
// Log these values from arguments list
String strLog = String.Concat("Reason: ", arguments.RemovedReason.ToString(), "
| Key-Name: ", arguments.CacheItem.Key, " | Value-Object: ",
arguments.CacheItem.Value.ToString());
}

}
}

Build this class library to generate assembly name of MyCachingWrapper.dll. Now we are ready to use this library in all ASP.Net web, WinForms and WPF applications.

Now let’s see examples of how this library can be commonly used in both ASP.Net Web Form and WinForm after adding reference of MyCachingWrapper.dll.

ASP.Net Page_Load:

protected void Page_Load(object sender, EventArgs e)
{
//
MyCache objCache = new MyCache();
String strUserName = objCache.GetMyCachedItem("USER_NAME") as String;
if (String.IsNullOrEmpty(strUserName))
{
List<String> lstFiles = new List<string>();
lstFiles.Add(HttpContext.Current.Request.MapPath("~/XmlFiles/ListOfUsers.xml"));

XElement x = XElement.Load(HttpContext.Current.Request.MapPath("~/XmlFiles/ListOfUsers.xml"));
var qry = from u in x.Elements("Users") where u.Element("UserCode").Value == "101" select u;
strUserName = qry.First().Element("UserName").Value;

// Add inside cache
objCache.AddToMyCache("USER_NAME", strUserName, MyCachePriority.Default, lstFiles);
}
this.lblUserName.Text = strUserName;
}

WinForm Form_Load:

private void frmDefault_Load(object sender, EventArgs e)
{
//
MyCache objCache = new MyCache();
String strFilePath =System.IO.Path.Combine(Environment.CurrentDirectory, "../../XmlFiles/ListOfUsers.xml");
String strUserName = objCache.GetMyCachedItem("USER_NAME") as String;
if (String.IsNullOrEmpty(strUserName))
{
List<String> lstFiles = new List<string>();
lstFiles.Add(strFilePath);

XElement x = XElement.Load(strFilePath);
var qry = from u in x.Elements("Users") where u.Element("UserCode").Value == "101" select u;
strUserName = qry.First().Element("UserName").Value;

// Add inside cache
objCache.AddToMyCache("USER_NAME", strUserName, MyCachePriority.Default, lstFiles);
}
this.lblUserName.Text = strUserName;
}

Sample ListOfUsers.xml File:

<?xml version="1.0"?>
<ListOfUsers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&quot; xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
<Users>
<UserCode>101</UserCode>
<UserName>Dan Brown</UserName>
</Users>
<Users>
<UserCode>102</UserCode>
<UserName>da Vinci</UserName>
</Users>
<Users>
<UserCode>103</UserCode>
<UserName>Monalisa</UserName>
</Users>
<Users>
<UserCode>104</UserCode>
<UserName>Shakespeare</UserName>
</Users>
<Users>
<UserCode>105</UserCode>
<UserName>William Wordsworth</UserName>
</Users>
</ListOfUsers>

Now we can debug above code and see other interesting things. You will see the usage of MemoryCache methods and its techniques to cache objects are similar to what we have been doing in ASP.Net cache so far. Also, we see how the same MyCache library is usable in both web and windows applications.

MemoryCache points worth mentioning:

  • MemoryCache.Default returns the single and same instance of in-memory ObjectCache through a static read-only property.

    public static MemoryCache Default { get; }

  • CacheEntryRemovedCallback signature is different than what we have seen in prior versions of ASP.Net. Refer to example. In the current callback method, one can see the following details when cache item is expired after 10 seconds.

CallbackArgumentsDetails

  • CacheItemPriority enum in .Net 4.0 is cleaner than what we have seen in prior versions of ASP.Net. Now, it is only Default and NotRemovable.
  • In prior version of ASP.Net, CacheDependency was used to monitor changes in any underlying objects like files, Sql database tables, rows, columns, etc. Now .Net 4.0 provides ChangeMonitor class which is ASP.Net neutral and has wider scope of monitoring dependent objects to expire cache items. However, CacheDependency is still there in ASP.Net 4.0. We should use other implementation of ChangeMonitor like HostFileChangeMontor in the above example.
  • The default implementation of MemoryCache does not give us flexibility to add regions along with keys. In order to use regions, you should extend MemoryCache.

Hope you all will appreciate .Net 4.0 caching feature.

Follow

Get every new post delivered to your Inbox.