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.
- Navigate to
/sitecore/templates/System/Layout/Sections
in the Sitecore Content Editor and open theCaching
template. - In the Builder tab, add a new
Integer
field to theCaching
section calledCacheDuration
. Check theShared
check box. - Save the
Caching
template. - Expand the
Caching
template in the site tree, expand theCaching
section node, and click on the newCacheDuration
field. Expand theData
section in the Content Editor and enterDuration (minutes)
for theTitle
.
Now the Cache Duration
setting is available on your Renderings as shown below.
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
- John West - Custom Caching Criteria with the Sitecore ASP.NET CMS
- dtb – How can I round up time to the nearest minute?