Saturday 19 April 2014

CacheCow 0.5 Released

[Level T1]

OK, finally CacheCow 0.5 (actually 0.5.1 as 0.5 was released by mistake and pulled out quickly) is out. So here is the list of changes, some of which are breaking. Breaking changes, however, are very easy to fix and if you do not need new features, you can happily stay at 0.4 stable versions. If you have moved to 0.5 and you see issues, please let me know ASAP. For more information, see my other post on Alpha release.

So here are the features:

Azure Caching for CacheCow Server and Client

Thanks to Ugo Lattanzi, we have now CacheCow storage in Azure Caching. This is both client and server. Considering calls to Azure Cache takes around 1ms (based on some ad hoc tests I have done, do not quote this as a proper benchmark), this makes a really good option if you have deployed your application in Azure. You just need to specify the cacheName, otherwise "default" cache will be used.

Complete re-design of cache invalidation

I have now put some sense into cache invalidation. Point is that strong ETag is generated for a particular representation of the resource while cache invalidation happens on the resource including all its representation. For example, if you send application/xml representation of the resource, ETag is generated for this particular representation. As such, application/json representation will get its own ETag. However, on PUT both need to be invalidated. On the other hand, in case of PUT or DELETE on a resource (let's say /api/customer/123) the collection resource (/api/customer) needs to be invalidated since the collection will be different. 

But how we would find out if a resource is collection or single? I have implemented some logic that infers whether the item is collection or not - and this is based on common and conventional routes design in ASP.NET Web API. If your routing is very custom this will not work. 

Another aspect is hierarchical routes. When a resource is invalidated, its parent resource will be invalidated as well. For example in case of PUT /api/customer/123/order/456 , customer resource will change too - if orders are returned as part of customer.  So in this case, not only the order collection resource but the customer needs to be invalidated. This is currently done in CacheCow.Server and will work for conventional routes.

Using MemoryCache for InMemory stores (both server and client)

Previously I have been using dictionaries for InMemory stores. The problem with Dictionary is that it just grows until system runs out of memory while MemoryCache limits its use of memory when system deals with a memory pressure.

Dependency of CachingHandler to HttpConfiguration

As I announced before, you need to pass the configuration to he CachingHandler on server. This should be an easy change but a breaking one.

Future roadmap and 0.6

I think we are now in a point where CacheCow requires a re-write for the features I want to introduce. One of such features is enabling Content-based ETag generation and cache invalidation. Currently Content-based ETag generation is there and can be used now but without content-based invalidation is not much use especially that in fact this now generates a weak ETag. Considering the changes required for achieving this, almost a re-write is required.

Please keep the feedbacks coming. Thanks for using and supporting CacheCow!


  1. Great library. I've set it up, and it's working great. However, I've noticed that when I do a PUT, POST or DELETE in a REST client, everything is great. But, when doing a PUT, POST or DELETE to the api endpoint using jQuery, the cache is not invalidated. Any ideas?

    1. Probably jQuery issue. Check if it's adding ?#_datetime at the end.

    2. Thanks - no, it's not adding anything to the end. I agree it's in jQuery - just can't find where.

      GET http://localhost:1573/api/assets/barcode/600100 HTTP/1.1
      Host: localhost:1573
      Connection: keep-alive
      User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36
      Accept: */*
      Accept-Encoding: gzip,deflate,sdch
      Accept-Language: en-US,en;q=0.8
      If-None-Match: W/"e50ad141ca814a67a9ab943825521b0b"
      If-Modified-Since: Tue, 22 Apr 2014 14:44:02 GMT

      Here's the response:
      HTTP/1.1 304 Not Modified
      Cache-Control: no-cache
      Pragma: no-cache
      Expires: -1
      ETag: W/"e50ad141ca814a67a9ab943825521b0b"
      Server: Microsoft-IIS/8.0
      X-AspNet-Version: 4.0.30319
      X-SourceFiles: =?UTF-8?B?YzpcdXNlcnNcaG9sZGVya1xkb2N1bWVudHNcdmlzdWFsIHN0dWRpbyAyMDEzXFByb2plY3RzXEVsbWJyb29rSW52ZW50b3J5XEVsbWJyb29rSW52ZW50b3J5XGFwaVxhc3NldHNcYmFyY29kZVw2MDAxMDA=?=
      X-Powered-By: ASP.NET
      Date: Tue, 22 Apr 2014 14:45:11 GMT

  2. How much is the expiry. Remember that until expiry is passed, client can re-use the resource - so for API resources it is best to set the expiry to zero. Can you please check and let me know?

  3. I think I'm zeroing in on this being the key... "But how we would find out if a resource is collection or single? I have implemented some logic that infers whether the item is collection or not - and this is based on common and conventional routes design in ASP.NET Web API. If your routing is very custom this will not work."

    My routing is not "very" custom, but it is custom.

    For example, /api/assets/{id} expires correctly, but /api/assets/barcode/{id} does not. How does one go about invalidating unconventional routes?


    1. Hi, Kyle. Can you please open an issue on GitHub We can discuss it better. Please show me your routes and your POST GET routes. It might very well be a bug in the CacheCow - although I believe I have unit tests testing this feature. Ideally please send a simple repro.

    2. Thanks - working on it. Hopefully will have it ready to go tomorrow.

    3. Perhaps /api/assets/{id}/barcode would be a better route?

  4. This comment has been removed by the author.

  5. Thanks. I've created an issue on the GIT.

  6. Great library! I started using it just this week and really like how flexible it is and simple to use. Awesome job!

    One thing I wanted to point out, in case it was not already known, is that I created a custom IRoutePatternProvider implementation and set it on the CacheHandler via this property:

    /// Provides route pattern and linked route pattern
    public IRoutePatternProvider RoutePatternProvider { get; set; }

    My custom class was never being invoked. Upon further inspection of the CacheHandler code it appears that the CacheHandler is never doing anything with the RoutePatterProvider property but rather relying on the internally set private variable _routePatternProvider. Additionally I cannot see where the LinkedRoutePatternProvider is being used either. The code I am looking at is from the master branch.

    I did look at the code in the WIP branch and it looks like the RoutePatternProvider is no longer in the CacheHandler class? Perhaps I just missed it.

    Again, great job and I love the library!


Note: only a member of this blog may post a comment.