Sitecore offers HTML caching for your components right out of the box with several different caching options to boost your site's performance. You can set different caching settings at the rendering-level such as enabling/disabling caching, caching per user, caching per data, etc. However, the caching duration for renderings is set at the site level and is not configurable at the rendering level. In this article I will show you how to add functionality to Sitecore to set cache duration at the rendering level.

Step 1 - Create the Cache Duration Setting in Sitecore

First we will create the new Cache Duration setting in Sitecore.

  1. Navigate to /sitecore/templates/System/Layout/Sections in the Sitecore Content Editor and open the Caching template.
  2. In the Builder tab, add a new Integer field to the Caching section called CacheDuration. Check the Shared check box.
  3. Save the Caching template.
  4. Expand the Caching template in the site tree, expand the Caching section node, and click on the new CacheDuration field. Expand the Data section in the Content Editor and enter Duration (minutes) for the Title.

Add Integer field called CacheDuration.

Set Title property of CacheDuration field.

Now the Cache Duration setting is available on your Renderings as shown below.

Cache Duration setting field.

Step 2 - Create RenderRenderingProcessor to Generate Cache Key

Now we will create a custom RenderRenderingProcessor to add renderings to the HTML cache based on their Cache Duration setting.

In your site’s solution, create a new class called SetRenderingCacheDuration as follows:

using System;  
using Sitecore.Diagnostics;  
using Sitecore.Mvc.Pipelines.Response.RenderRendering;

namespace Sample.RenderRenderingProcessors  
{
  public class SetRenderingCacheDuration : RenderRenderingProcessor
  {
    private const string ParamKey = "CacheDuration";

    public override void Process(RenderRenderingArgs args)
    {
      Assert.ArgumentNotNull(args, nameof(args));
      if (args.Rendered || !args.Cacheable || string.IsNullOrEmpty(args.CacheKey)) return;

      var rendering = args.PageContext.Database.GetItem(args.Rendering.RenderingItem.ID);
      if (string.IsNullOrEmpty(rendering?[ParamKey])) return;

      int duration;
      if (!int.TryParse(rendering[ParamKey], out duration) || duration <= 0) return;

      var timeStamp = RoundUp(DateTime.UtcNow, TimeSpan.FromMinutes(duration));
      args.CacheKey += "_#timeStamp:" + timeStamp.ToString("s");
    }

    private static DateTime RoundUp(DateTime dateTime, TimeSpan timeSpan)
    {
      return new DateTime((dateTime.Ticks + timeSpan.Ticks - 1) / timeSpan.Ticks * timeSpan.Ticks);
    }
  }
}

Add the SetRenderingCacheDuration RenderRenderingProcessor into your web.config. Make sure that you add it after Mvc.Pipelines.Response.RenderRendering.GenerateCacheKey. Here is an example patch file for reference:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">  
  <sitecore>
    <pipelines>
      <mvc.renderRendering>
        <processor type="Sample.RenderRenderingProcessors.SetRenderingCacheDuration, Sample"
                   patch:after="processor[@type='Sitecore.Mvc.Pipelines.Response.RenderRendering.GenerateCacheKey, Sitecore.Mvc']" />
      </mvc.renderRendering>
    </pipelines>
  </sitecore>
</configuration>  

Build and publish your solution. Navigate to a rendering in the site tree, ensure that Cacheable is checked, and enter a duration in the Duration (minutes). Save the rendering and republish your site.

Details

This feature works by appending on to the cache key generated by Sitecore when a rendering is cached. The RenderingProcessor uses the RoundUp function to calculate an expiration time for the cache item and appends that on to the cache key.

For example, if you configure a Controller Rendering called “SampleRendering” to have a Cache Duration of 10 minutes, the cache key will be generated similar to this at 12:00 a.m.: controller::Sample#SampleRendering_#timeStamp:2016-02-22T00:10:00

When the rendering is accessed again at 12:02 a.m., 12:07 a.m., and 12:09 a.m., the cache key will continue to be generated the same, since those times rounded up to the nearest 10 minutes is 12:10 a.m. As a result, the rendering will not be regenerated and will be grabbed from the cache.

When a request comes in at 12:11 a.m., the cache key will be generated as controller::Sample#SampleRendering_#timeStamp:2016-02-22T00:20:00 and the rendering will be generated again from scratch and cached until 12:20 a.m.

Limitations

The Cache Duration will apply to all instances of a rendering and is not configurable on a per-instance basis in Presentation Details. For example, if you add two instances of the Sample Rendering to a page, both will cache for the same duration set on the rendering item in the Content Editor.

As described in the Details section, the rendering-level cache duration works by effectively setting an expiration time in the cache key. Once the expiration time has passed, the item will never be read from the cache again and will remain in the cache until it is evicted by the framework, the site-level cache lifetime has elapsed, or the HtmlCacheClearAgent runs. By default, the site-level cache has an eternal lifetime and the HtmlCacheClearAgent is not set to run at all, so be careful that you do not bloat your cache by setting the Cache Duration unnecessarily low or unnecessarily combining it with too many of the other caching options.

References