Search code examples
c#cachingenterprise-library

Caching fails after FileDependency file changes


I am using the Microsoft EnterPrise Library Caching library (Version 5) with a FileDependency.

On the class that I want cached, I have a static property that will either return the item from the cache, or else create a new class and add it to the cache.

This initially works well and the class is created once, and from then on, the cached copy is returned. However once the dependency file changes the cached item is never returned.

I have put together a sample program below to illustrate the issue.

The output from this is

999 cached , 1 uncached
999 cached , 1001 uncached

I would expect the results to be

 999 cached , 1 uncached
1998 cached , 2 uncached

It would look like the object is added back to the cache, but is then immediately deleted as expired.

Any ideas why?

using System;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Caching;
using Microsoft.Practices.EnterpriseLibrary.Caching.Expirations;

namespace TestCache
{
  static class Program
  {
    [STAThread]
    static void Main()
    {
        Cache.Create();

        for (int i = 0; i < 1000; i++)
            TestClass.Current.DummyMethod();
        Console.WriteLine(String.Format("{0} cached , {1} uncached", TestClass.CachedItems, TestClass.UncachedItems));

        System.IO.File.AppendAllText(Cache.dependencyFileName, "Test");

        for (int i = 0; i < 1000; i++)
            TestClass.Current.DummyMethod();           
        Console.WriteLine(String.Format("{0} cached , {1} uncached", TestClass.CachedItems, TestClass.UncachedItems));

        Console.ReadLine();
    }
}

 public class Cache
{
    public static CacheManager cacheManager = null;
    public static string dependencyFileName;
    public static FileDependency objFileDependency;

    public static void Create()
    {
        var builder = new ConfigurationSourceBuilder();

        builder.ConfigureCaching()
               .ForCacheManagerNamed("TestCache")
               .UseAsDefaultCache()
               .StoreInMemory();

        var configSource = new DictionaryConfigurationSource();
        builder.UpdateConfigurationWithReplace(configSource);
        EnterpriseLibraryContainer.Current = EnterpriseLibraryContainer.CreateDefaultContainer(configSource);

        cacheManager = (CacheManager)EnterpriseLibraryContainer.Current.GetInstance<ICacheManager>("TestCache");

        dependencyFileName = "testCache.xml";
        if (!System.IO.File.Exists(dependencyFileName))
            using (System.IO.File.Create(dependencyFileName)) { }

        objFileDependency = new FileDependency(dependencyFileName);
    }
}

public class TestClass
{

    public static int CachedItems =0;
    public static int UncachedItems = 0;

    public void DummyMethod()
    {
    }

    public static TestClass Current
    {
        get
        {
            TestClass current = (Cache.cacheManager.GetData("Test") as TestClass);
            if (current != null)
                CachedItems++;
            else
            {
                UncachedItems++;
                current = new TestClass();
                Cache.cacheManager.Add("Test", current, CacheItemPriority.Normal, null, new ICacheItemExpiration[] { Cache.objFileDependency });
            }
            return current;
        }
    }

}

}


Solution

  • Your issue is that you are using a static FileDependency. This is causing the LastUpdateTime of the FileDependency to never be updated which in turn causes all items added to the cache to show as being expired (HasExpired() == true). Even though you are adding items to the cache since they are expired you can never retrieve them.

    The solution is to use a new FileDependency object for all additions to the cache. The easiest change would be to replace the objFileDependency field with a property. Using your existing names and approach, the code would look like:

    public class Cache
    {
        public static CacheManager cacheManager = null;
        public static readonly string dependencyFileName = "testCache.xml";            
    
        public static FileDependency objFileDependency
        {
            get
            {
                return new FileDependency(dependencyFileName);
            }
        }
    
        public static void Create()
        {
            var builder = new ConfigurationSourceBuilder();
    
            builder.ConfigureCaching()
                   .ForCacheManagerNamed("TestCache")
                   .UseAsDefaultCache()
                   .StoreInMemory();
    
            var configSource = new DictionaryConfigurationSource();
            builder.UpdateConfigurationWithReplace(configSource);
            EnterpriseLibraryContainer.Current = EnterpriseLibraryContainer.CreateDefaultContainer(configSource);
    
            cacheManager = (CacheManager)EnterpriseLibraryContainer.Current.GetInstance<ICacheManager>("TestCache");
    
            if (!System.IO.File.Exists(dependencyFileName))
                using (System.IO.File.Create(dependencyFileName)) { }
        }
    }