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 yourweb.config
. Make sure that you add it afterMvc.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 theDuration (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.
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.
@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.
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?