A quick look at CacheCow

I wanted to give this library a go since I had quite a few posts about it and log what I ended up doing with it as well as key features I need to take into account and have knowledge of.

CacheCow stores cache data on the Client-side while the Server-side will merely provide caching directives which we can rely on the defaults or tell how and when we want to cache our resources. What I think is kind of cool from this library is how it encourages the developer and facilitates deferring handlign cache state validation out of Application code into specific components, it provides a degree of flexibility and extensibility for it.

In-Memory and SQL (I assume MS SQL Server) are the only cache store options available at the time of writing this post, however, the library does provide a mechanism to define our own.

Concepts and Features

There are a bunch of Concept and Definitions which I personally find a mix between standard and abstract concepts as well as componentes and elements particular to the library, some of them I believe are worth listing here:

General

Library specific

So, there are two things I wanted to try:

I have put together I small Web Application to test these features from CacheCow.

The simplest way to get going is simply install the package and register the library elements with unity and annotate the controller action of choice as follows:

// Register with Unity
services.AddHttpCachingMvc(); // comes right after the Mvc registration.

and then, decorate our controller action and let the library defaults work.

[HttpGet]
[HttpCacheFactory(20)] // This is attr we are looking for, 20 is the TTL is seconds.
public async Task<ActionResult<IEnumerable<ActivityLogEntryViewModel>>> Index()
{
    await Task.Delay(5000);
            
    return Json(_logsService.GetActivityLogs().Select(l => new ActivityLogEntryViewModel {
        EventTimestamp = string.Concat(l.EventTimestamp.ToShortDateString(), " ", l.EventTimestamp.ToShortTimeString()),
        UserIdentity = l.Who.ToString(),
        SystemArea = l.SystemArea,
        UserAction = l.UserAction
}));

Having defined and register our Timed ETag Extractor, we can put it to use, our Controlle method would look like:

[HttpGet]
[HttpCacheFactory(20, ViewModelType = typeof(ActivityLogEntryViewModel))]
public async Task<ActionResult<IEnumerable<ActivityLogEntryViewModel>>> Index2()

The type specified for ViewModelType has to match the one used in the ITimedETagExtractor implementation. In our Timed ETag Extractor, it is this line that calculatest the value of the ETag.

foreach (var b in SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(viewModel.EventTimestamp)))
{
    tagValue.Append(b.ToString("x2"));
}
return new TimedEntityTagHeaderValue(tagValue.ToString());

If the resource has changed, the value calculated would differ from the one on the client side which is the whole purpose of the validation, additionally we could use ITimedETagQueryProvider if we want to validate the resource in the backend store.