Caching

Caching is about improve applications performance. The most expensive performance costs of the applications are related with the data retrieving, typically when this data requires to be moved a cross the network or loaded from disk. But some data have an slow changing behavior (a.k.a non-volatile) and doesn't requires to be re-read with the same frequency of the volatile data.

So, to improve your application performance and handling this "nonvolatile" data from a pretty clean approach, Catel comes with a CacheStorage<TKey, TValue> class. Notice that the first generic parameter is the type of the key and the second the type of the value the will be store, just like a Dictionary<TKey, TValue> but CacheStorage isn't it just a Dictionary. This class allows you to retrieve data and storing it into the cache with single statement and also helps you to handle expiration policy if you need it.

Initializing a cache storage

To initialize a cache storage field into your class use the follow code:

private readonly CacheStorage<string, Person> _personCache = new CacheStorage<string, Person>(allowNullValues: true);

Retrieve data and storing into cache with single statement

To retrieve data and storing into a cache with a single statement use the follow code:

var person = _personCache.GetFromCacheOrFetch(Id, () => service.FindPersonById(Id));

When this statement is executed more than once times with the with the same key, the value will be retrieved from the cache storage instead from the service call. The service call will be executed just the first time or if the item is removed from the cache manually or automatically due by the expiration policy.

Using cache expiration policies

The cache expiration policies adds a removal behavior to the cache storage items. A policy signals that an item is expired to makes that cache storage removes the item automatically.

A default cache expiration policy initialization code can be specified during cache storage initialization constructor:

CacheStorage<string, Person> _personCache = new CacheStorage<string, Person>(() => ExpirationPolicy.Duration(TimeSpan.FromMinutes(5)), true);

You can specify an specific expiration policy for an item when it's storing:

_personCache.GetFromCacheOrFetch(id, () => service.GetPersonById(id), ExpirationPolicy.Duration(TimeSpan.FromMinutes(10)));

The default cache policy specified at cache storage initialization will be used if during item storing the expiration policy is not specified.

 Build-in expiration policies

Catel comes with build-in expiration policies. They are listed in the follow table:

Expiration policyTypeDescriptionInitialization code sample
AbsoluteExpirationPolicyTime-baseThe cache item will expire on the absolute expiration DateTime
ExpirationPolicy.Absolute(new DateTime(21, 12, 2012))
DurationExpirationPolicyTime-baseThe cache item will expire using the duration TimeSpan to calculate the absolute expiration from DateTime.Now
ExpirationPolicy.Duration(TimeSpan.FromMinutes(5))
SlidingExpirationPolicyTime-baseThe cache item will expire using the duration TimeSpan to calculate the absolute expiration from DateTime.Now, but everytime the item is requested, it is expanded again with the specified TimeSpan
ExpirationPolicy.Sliding(TimeSpan.FromMinutes(5))
CustomExpirationPolicyCustomThe cache item will expire using the expire function and execute the reset action if is specified. The example shows how create an sliding expiration policy with a custom expiration policy.
var startDateTime = DateTime.Now;
var duration = TimeSpan.FromMinutes(5);

ExpirationPolicy.Custom(() => DateTime.Now > startDateTime.Add(duration), () => startDateTime = DateTime.Now);
CompositeExpirationPolicyCustomCombines several expiration policy into a single one. It can be configured to expires when any policy expires or when all policies expires.
new CompositeExpirationPolicy().Add(ExpirationPolicy.Sliding(
TimeSpan.FromMinutes(5))).Add(ExpirationPolicy.Custom(()=>...))

Implementing your own expiration cache policy

If the CustomExpirationPolicy is not enough, you can implement you own expiration policy to makes that cache item expires triggered from a custom event. You are also able to add some code to reset the expiration policy if the item is read from the cache before it expires (just like SlidingExpirationPolicy does).

To implement an expiration cache policy use the follow code template:

public class MyExpirationPolicy : ExpirationCachePolicy
{
   public MyExpirationPolicy():base(true)
   {
   }

   public override bool IsExpired
   {
      get
      {
         // Add your custom expiration code to detect if the item expires
      }
   }

   public override void OnReset()
   {
      // Add your custom code to reset the policy if the item is read.
   }
}

The base constructor have a parameter to indicates if the policy can be reset. Therefore, is you call the base constructor with false then the OnReset method will never called.