Published:
Out of the box, Sitecore’s Html Caching is pretty powerful, but it does have some limitations. In my most recent project I found that there were some Variations of the Cache Key that would be useful in the project. First off I want to explain exactly how Html Caching works with sitecore. It works at the rendering level. So you have built for example a controller rendering (Mvc), that pulls the most recent articles on your homepage. If all you rely on to pull content is if it’s been published to your content delivery database, than all you would need in this scenario, is to mark the item as cacheable. What this would do, is create a key, something that represents the specific rendering, and then the code would check for that specific string value key, and see if there’s html assigned to it. If it’s the first time loading the component, it will create the cache key, and then pull the html content. Once it has the html content, it will create html cache using the key as an identifier, and store the returned html back.
The reason that will work in that scenario is because the html cache gets completely cleared out, anytime you publish content to the content delivery server from Sitecore. So if your article only relies on them being in content delivery server, when you do a publish of new article content (or any publish really), it will clear the html cache, and the cache will get updated to include any new articles on the next page load.
But what do you do if you rely on publishing content, not only when it’s in your content delivery server, but also on other variables. Example in our environment, we use a Live Date, which is set to a date in the future. For example, if you want content to show up on a specific date even after it’s already in the content delivery server, you could set this custom date to do so. Your repositories for pulling data from Sitecore, obviously would need to check this date to ensure content would display or not. However doing it like this creates an issue with Html Caching, because no longer does the Publish to your CD server control when content displays. You now need to somehow clear the cache more regularly, on some form of timed interval. You can still of course rely on publishing to the Content delivery server triggering this refresh, but if that only happen about once a week, you will need to clear your cache every 12 to 24 hours (assuming you are only using the Date field type, if you are however using date time, you might need to clear cache hourly). Out of the box, Sitecore does not include an option to set a Timeout value, however there is a fairly easy way to update this value and provide support for it.
Out of the Box Sitecore only includes the following options:
As you can see there is no way out of the box to set a Timeout value. But you can customize the options by going to the following location: /sitecore/templates/System/Layout/Sections/Caching, which brings you to an interface you all should be familiar with. You can specify additional fields. Lets go ahead and create a new field called “Timeout”, which is a Single-Line text field. Now that you have this value being stored for the rendering, you’ll need to pull it out of Sitecore when it creates the cache, so it can set the timeout value to this value, rather than the default value.
To do so, it’s pretty easy, you just need to extend the AddRecordedHtmlToCache pipeline and override the GetTimeout method.
using Sitecore.Mvc.Pipelines.Response.RenderRendering;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Site.Infrastructure.Pipelines.Renderings
{
public class AddRecordedHtmlToCache : Sitecore.Mvc.Pipelines.Response.RenderRendering.AddRecordedHtmlToCache
{
protected override TimeSpan GetTimeout(RenderRenderingArgs args)
{
TimeSpan result;
return TimeSpan.TryParse(args.Rendering.RenderingItem.InnerItem["Timeout"], out result) ? result : args.Rendering.Caching.Timeout;
}
}
}
Once you’ve done that, all you need to do is update your patch file to apply this change:
<?xml version="1.0"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<mvc.renderRendering>
<processor patch:instead="processor[@type='Sitecore.Mvc.Pipelines.Response.RenderRendering.AddRecordedHtmlToCache, Sitecore.Mvc']"
type="Site.Infrastructure.Pipelines.Renderings.AddRecordedHtmlToCache, Site.Infrastructure" />
</mvc.renderRendering>
</pipelines>
</sitecore>
</configuration>
Alright now you should be able to set the Timeout for the html cache for your rendering. But what if you have a controller rendering that shows a different set of article content depending on the page you are on. For example, lets say you have a component that shows most recent by category. Now we would still want to timeout the cache at set intervals and clear cache on publish that is standard with Sitecore, but now we would also like to vary the results by either parameters or even by url. Now varying the rendering by rendering parameters is build into the default Sitecore Html Caching logic. But for this example, we will pretend that doesn’t exist, also you may not want to use a rendering parameter, but just determine the category based on the current context.
Anyways, so in order to pull this off, we will need to create a new VaryBy (variation) of the cache key. So by default a rendering will have a cache key that’s unique to the rendering. Then you can specify variations of that cache key, so for example vary by parameter, will create varied cache key’s based on the parameters for that specific rendering. So if you had a rendering parameter that had page size set to 10, and then another rendering of the same component on a different page set to 20, it would built a unique cache key for those two different components. However subsequent requests to those components would render cached html. Also if you placed a rendering on another page of the same type with the same rendering parameter values, it will pull from Cache.
So in order to create a new variation, in this example it will vary by Url, you will need to first modify the Cache template, similar to what we did for adding a Single-Line Text field called “Timeout”. You can access this template here /sitecore/templates/System/Layout/Sections/Caching
. You will need to create a new field called VaryByUrl
, and it will be of type “Checkbox”.
Once that change is made you will need to then setup the code to include the additional variation types you are specifying. To do that, you will need to extend the GenerateCacheKey.cs
pipeline in RenderRendering
pipeline group.
using Sitecore;
using Sitecore.Data.Items;
using Sitecore.Mvc.Pipelines.Response.RenderRendering;
using Sitecore.Mvc.Presentation;
using Sitecore.Web;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Site.Infrastructure.Pipelines.Renderings
{
public class GenerateCacheKey : Sitecore.Mvc.Pipelines.Response.RenderRendering.GenerateCacheKey
{
private const string VARYBYURL = "VaryByUrl";
protected override string GenerateKey(Rendering rendering, RenderRenderingArgs args)
{
string cacheKey = base.GenerateKey(rendering, args);
Item renderingItem = rendering.RenderingItem.InnerItem;
if (!string.IsNullOrEmpty(renderingItem[VARYBYURL]))
{
cacheKey += "_#url:" + Sitecore.Context.RawUrl;
}
return cacheKey;
}
}
}
And then you will just update the patch file to include this as a patch to the default Sitecore pipelines:
<?xml version="1.0"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<mvc.renderRendering>
<processor patch:instead="processor[@type='Sitecore.Mvc.Pipelines.Response.RenderRendering.GenerateCacheKey, Sitecore.Mvc']"
type="Site.Infrastructure.Pipelines.Renderings.GenerateCacheKey, Site.Infrastructure" />
</mvc.renderRendering>
</pipelines>
</sitecore>
</configuration>
That’s it, you can use this approach to add all kinds of variations for the creation of these Sitecore Html Caching Keys. Some other variations that you might want to have include:
Happy Coding!