Exploring Akavache

Akavache is a key-value store/cache. It’s compatible with flavours of Windows including the desktop, WinRT and Windows Phone 8 as well as iOS, Mac and Android via Xamarin. It supports async await as well as RX observable.

Let’s code

We interact with Akavache via the BlobCache static class but before we do anything with Akavache we need to setup the application name. So at the first opportunity, such as when your applications starts you should supply Akavache with your application name.

BlobCache.ApplicationName = "MyApplicationName";

There are several different caches that we can use on the BlobCache object. Each implements the IBlobCache interface.

  • The InMemory property is used for caching anything which is to be stored (as the name suggests) in memory and thus lost when the application shuts down.
  • The LocalMachine is used to store data that is not related to the user’s account.
  • The Secure is encrypted and is used to anything you want to store in a more secure manner.
  • Finally the UserAccount is used to store data on a per user basis and can be part of a roaming profile.

As stated on the Akavache readme.md, “on the desktop, your application’s data will be stored in the %AppData%\[ApplicationName] and %LocalAppData%\[ApplicationName]”.

Inserting data into the cache

There are several insertion methods (instance and extension methods) and overloads for each. I’m not going to go through each method and their overloads, instead let’s look at the insertion method you’ll most likely start with – inserting a single object.

BlobCache.UserAccount.InsertObject("someObject", new SomeObject());

We supply a key, in this case the string someObject followed by an object. We can optionally supply a DateTimeOffset or TimeSpan to use as an expiration time, i.e. when the data is ejected from the cache.

Ofcourse, if we insert more than one item with the same key, we’re simply going to overwrite the existing item, therefore updating the cache with the last inserted value.

Getting data from the cache

Once we’ve inserted items in the cache we’ll need a way to retrieve them. As can be seen from the InsertObject method we supply a key for our cached item. So we obviously use the same key to get the value from the cache. Akavache uses an asynchronous model for getting items from a cache so uses either an IObservable (the RX way) or getting values using async await. Here’s an example using the RX method

SomeObject result = null;
BlobCache.UserAccount.GetObject<SomeObject>("someObject")
   .Subscribe(i => result = i);

and here’s the same thing using async await

SomeObject result = await BlobCache.UserAccount.GetObject<SomeObject>("someObject")

Getting data which is currently not cached

Obviously we don’t always start an application with the items already in the cache. So a common requirement is to query the cache for a value, if it doesn’t exist then get it from somewhere and then place it in the cache. Akavache offers a GetOrFetchObject method which allows the developer to to do just this. First we try to get an item from the cache and if it does not exist in the cache we can supply a Func<Task<T>> or Func<IObservable<T>> to get the item from somewhere else and it’s then automatically added to the cache for us.

SomeObject result = null;
BlobCache.UserAccount.GetOrFetchObject(
   "someObject", 
   () => Task.Factory.StartNew(() => new SomeObject()))
   .Subscribe(o => result = o);

// or using async await

SomeObject result = await BlobCache.UserAccount
   .GetOrFetchObject("someObject", 
   () => Task.Factory.StartNew(() => new SomeObject()));

We can also pass an expiration DateTimeOffset to the above method.

Note: GetOrFetchObject and GetOrCreateObject appear to do the same thing, both calling GetOrFetchObject which takes a Func<IObservable>. The former simply converts a Task<T> to an and IObservable<T> and the latter converts a Func<T> to an IObservable<T> also.

An interesting other “get” method to look at is GetAndFetchLatest. This will attempt to get a value from the cache and at the same time will use the supplied Func to get the value from some alternate place. So for example, let’s say you’re going to get a value from a webservice. This will return the current cached version (if one exists) and at the same time try to get the current value from the webservice. Hence two items may be returned.

In use…

BlobCache.UserAccount.GetAndFetchLatest(
   "someObject", () => Task.Factory.StartNew(() => new SomeObject()))
   .Subscribe(i => result = i);

In the above code the result = i will be called twice (assuming we’ve already inserted an object with the key “someObject” into the cache). As you’d expect from the previous description of this method, the first call would contain cached “someObject” value and the second would be the new object we’ve created in the task.

Removing items from the cache

Apart from setting an expiration for items as they’re added to the cache we can also use the method Invalidate to remove specific key values from the cache or InvalidateAll to remove/clear all items from the cache.

For example

BlobCache.UserAccount.Invalidate("someObject");