POST

ASP.NET Core Distributed Cache Tag Helper

The anxiously awaited ASP.NET Core RC2 has finally landed and with it we have a shiny new tag helper to explorer.

We previously talked about the Cache Tag Helper and how it allows you to cache the output from any section of a Razor page. While the Cache Tag Helper is powerful and very useful, it is limited in that it uses an instance of IMemoryCache which stores cache entries in memory in the local process. If the server process restarts for some reason, the contents of the cache will be post. Also, if your deployment consists of multiple servers, each server would have its own cache, each potentially containing different contents.

Distributed Cache Tag Helper

The cache tag helper left people wanting more. Specifically they wanted to store the cached HTML in a distributed cache like Redis. Instead of complicating the existing Cache Tag Helper, the ASP.NET team enabled this use-case by adding a new Distributed Cache Tag Helper.

Using the Distributed Cache Tag Helper is very similar to using the Cache Tag Helper:

1234

<distributed-cachename="MyCache"><p>Something that will be cached</p> @DateTime.Now.ToString()</distributed-cache>

The name property is required and the value should be unique. It is used as a prefix for the cache key. This differs from the Cache Tag Helper which uses an automatically generated unique id based on the location of the cache tag helper in your Razor page. The auto generated approach cannot be used with a distributed cache because Razor would generate different unique ids for each server. You will need to make sure that you use a unique name each time you use the distributed-cache tag helper. If you unintentionally use the same name in multiple places, you might get the same results in 2 places.

For example, see what happens when 2 distributed-cache tag helpers with the same name:

123456789

<distributed-cachename="MyCache"><p>Something that will be cached</p> @DateTime.Now.ToString()</distributed-cache><distributed-cachename="MyCache"><p>This should be different</p> @DateTime.Now.ToString()</distributed-cache>

If you are really curious about the how cache keys are generated for both tag helpers, take a look at the CacheTagKey Class.

The vary-by-* and expires-* attributes all work the same as the Cache Tag Helper. You can review those in my previous post.

Configuring the Distributed Cache

Unless you specify some additional configuration, the distributed cache tag helper actually uses a local process in memory cache. This might seem a little strange but it does help with the developer workflow. As a developer, I don't need to worry about standing up a distributed cache like Redis just to run the app locally. The intention of course is that a true distributed cache would be used in a staging/production environments.

The simplest approach to configuring the distributed cache tag helper is to configure a IDistributedCache service in the Startup class. ASP.NET Core ships with 2 distributed cache implementations out of the box: SqlServer and Redis.

As a simple test, let's try specifying a SqlServerCache in the Startup.ConfigureServices method:

Now when I visit the page that contains the distributed-cache tag helper, I get the following error:

InvalidOperationException: Either absolute or sliding expiration needs to be provided.

The SQL Server implementation requires us to specify some form of expiry. No problem, let's just add the those attributes to the tag helper:

12345678910

<distributed-cachename="MyCacheItem1"expires-after="TimeSpan.FromHours(1)"><p>Something that will be cached</p> @DateTime.Now.ToString()</distributed-cache><distributed-cachename="MyCacheItem2"expires-sliding="TimeSpan.FromMinutes(30)"><p>This should be different</p> @DateTime.Now.ToString()</distributed-cache>

Now the page renders properly and we can see the contents in SQL Server:

Note that since the key is hashed and the value is stored in binary, the contents of the table in SQL server are not human readable.

I suspect that this added level of customization won't be needed by most people.

Conclusion

The Distributed Cache Tag Helper provides an easy path to caching HTML fragments in a distributed cache. Out of the box, Redis and SQL Server are supported. Over time, I expect that a number of alternative distributed cache implementations will be provided by the community.