Thursday, April 29, 2010

Microsoft Enterprise Library Caching Gotcha

Recently, a developer where I work added caching to some methods that retrieve contacts from a table in our database. Afterwords, a tester complained that when he went to one screen that allows selecting a contact, he saw the text "[Select a contact]" repeated. Not only that, every time he returned to that screen, the problem became worse.

Before caching was added, the method that retrieves the list of contacts got them from the database, then it added the text "[Select a contact]" to the beginning of the list. When caching was added, the list was retrieved from the cache (if available), and then the text "[Select a contact]" was added to the beginning.

It turns out that when a list is added to the cache, and then later the list is modified, that modified list will be returned the next time the cache is accessed. Here is some sample code to make it more clear:

private void btnTestCaching_Click(object sender, EventArgs e)
{
List<string> testList = TestCaching(1);
PrintList(testList);
testList = TestCaching(2);
PrintList(testList);
}

private void PrintList(List<string> testList)
{
foreach (string s in testList)
{
Debug.WriteLine(s);
}
}

private List<string> TestCaching(int id)
{
ICacheManager cache = CacheFactory.GetCacheManager();
List<string> testList = cache["TestList"] as List<string>;
if (testList == null)
{
testList = new List<string>();
testList.Add("Test 1");
testList.Add("Test 2");
testList.Add("Test 3");

AbsoluteTime expiry = new AbsoluteTime(new TimeSpan(2, 0, 0, 0));
cache.Add("TestList", testList, CacheItemPriority.High, null, new ICacheItemExpiration[] { expiry });
}
testList.Add("[Select a contact] " + id.ToString());
return testList;
}
I added a counter to make it slightly more clear what's happening. Here's the output from Visual Studio:

Test 1
Test 2
Test 3
[Select a contact] 1
Test 1
Test 2
Test 3
[Select a contact] 1
[Select a contact] 2


I was surprised by the outcome. I thought that the list would be persisted only when cache.Add() is called, apparently that's not the case.

No comments: