Skip to main content

Microsoft

Rendering-Level Cache Duration in Sitecore MVC

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 an Integer field called CacheDuration to the Caching item.

Add an Integer field called CacheDuration to the Caching item. (Click to view full size)


Set the Title property of the Cache Duration field to "Duration (minutes)".

Set the Title property of the CacheDuration field to Duration (minutes). (Click to view full size)


Now the Cache Duration setting is available on your Renderings as shown below.
The Cache Duration setting is now available on all renderings.

The Cache Duration setting is now available on all renderings. (Click to view full size)

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.

  1. 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);
    }
  }
}
  1. 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>
  1. Build and publish your solution.
  2. 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

Thoughts on “Rendering-Level Cache Duration in Sitecore MVC”

  1. I’m fuzzy on how this might work. I understand the concept. However, Sitecore, it seems, limits caching of renderings to 60 seconds (and i have not found a way to change this). This means the item will be gone from cache in 60 seconds, regardless of what hacking you might do around the cache key.
    You can ask for whatever hacked-up key you want. After 60 seconds, the cached item is gone and will be re-executed.

  2. @Deane I wonder if there is another issue on your solution, as what you describe has not been my experience nor can I find any corroborating documentation to back that up. The cache timeout is definitely not 60 seconds, and this solution works just fine. I’d check my configs and be sure that you don’t have something configured in your rendering to vary by data or some other factor.

  3. I’ve tested this method extensively and it does indeed cache according to the timeout set in the Cache Duration field. One caveat with this method is that you cannot set a Cache Duration longer than the Caching.HtmlLifetime setting in your Sitecore config; if your Caching.HtmlLifetime is shorter than the Cache Duration set on your rendering, the Caching.HtmlLifetime will take precedence.
    Another setting that could be causing issues for you is the interval on the Sitecore.Tasks.HtmlCacheClearAgent agent in your Sitecore config.
    Are either of these settings set to 60 seconds in your Sitecore config?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Corey Smith, Sitecore MVP & Lead Technical Consultant

I'm a Sitecore MVP and Lead Technical Consultant at Perficient focusing on Sitecore and custom .NET development.

More from this Author

Categories
Follow Us
TwitterLinkedinFacebookYoutubeInstagram