In Sitecore you can control the caching of your sublayouts in many different ways.
Checking the “Cacheable” box allows you you vary the cache by data (data source), device, login (anonymous users have a different cached version from named users), param (item parameters), query string or user (each user has his own version).
Caching is an area that hasn’t changed much since Sitecore 5, which is why this code should work on any Sitecore version. However, For caching in MVC, Sitecore have implemented a different approach. See CUSTOM CACHE CRITERIA WITH MVC IN THE SITECORE ASP.NET CMS by John West for more information.
But what if you wish to vary the cache on another parameter, say, the contents of a cookie?
My colleague, Niclas Awalt, solved this for me a while ago.
STEP 1: SETTING UP SITECORE
First we need to define the name of the cookie to vary by. This is done in the “Parameters” field on the sublayout:
The “VaryByCookie” defines my caching key, and the “Mycookie” defines the cookie to vary by.
STEP 2: CREATE A CUSTOM SUBLAYOUT
This custom sublayout contains the code that determines if the sublayout is cacheable, and if the “VaryByCookie” value is set, and if so, creates a new cache key based on the contents of the cookie:
using System.Collections.Specialized; using System.Text; namespace MyNamespace { public class CustomSublayout : Sitecore.Web.UI.WebControls.Sublayout { private string _varyByCookies; private string VaryByCookies { get { return _varyByCookies ?? (_varyByCookies = GetVaryByCookiesParameter()); } } public override string GetCacheKey() { Sitecore.Sites.SiteContext site = Sitecore.Context.Site; if (!Cacheable) return base.GetCacheKey(); if (site != null && (!site.CacheHtml)) return base.GetCacheKey(); if (SkipCaching()) return base.GetCacheKey(); if (string.IsNullOrEmpty(VaryByCookies)) return base.GetCacheKey(); var cacheKey = base.GetCacheKey() + BuildCookieValueString(); return cacheKey; } private string BuildCookieValueString() { StringBuilder stringBuilder = new StringBuilder(); foreach (var cookieName in VaryByCookies.Split('|')) { stringBuilder.Append(GetCookieValue(cookieName, "0NoValue0")); } if (stringBuilder.Length > 0) stringBuilder.Insert(0, "_#cookies:"); return stringBuilder.ToString(); } private string GetCookieValue(string cookieName, string defaultValue) { var cookieValue = Context.Request.Cookies[cookieName]; return string.Concat(cookieName, cookieValue == null ? defaultValue : cookieValue.Value); } private string GetVaryByCookiesParameter() { NameValueCollection parameters = Sitecore.Web.WebUtil.ParseUrlParameters(this.Parameters); return parameters["VaryByCookie"] ?? string.Empty; } } }
STEP 3: HOOK UP THE NEW SUBLAYOUT:
Next step is to replace the Sitecore Sublayout rendering control with our own.
First, create a small rendering type class:
using System.Collections.Specialized; using System.Web.UI; namespace MyNamespace { public class CustomSublayoutRenderingType : Sitecore.Web.UI.SublayoutRenderingType { public override Control GetControl(NameValueCollection parameters, bool assert) { CustomSublayout sublayout = new CustomSublayout(); foreach (string name in parameters.Keys) { string str = parameters[name]; Sitecore.Reflection.ReflectionUtil.SetProperty(sublayout, name, str); } return sublayout; } } }
Then, in the web.config, in the <renderingControls> section, call our new sublayout rendering control:
<renderingControls> <control template="method rendering" type="Sitecore.Web.UI.WebControls.Method, Sitecore.Kernel" propertyMap="AssemblyName=assembly, ClassName=class, MethodName=method" /> <!-- OUR NEW RENDERING --> <control template="sublayout" type="MyNamespace.CustomSublayoutRenderingType, MyDll" propertyMap="Path=path" /> <!-- OUR NEW RENDERING --> <control template="url rendering" type="Sitecore.Web.UI.WebControls.WebPage, Sitecore.Kernel" propertyMap="Url=url" /> <control template="xsl rendering" type="Sitecore.Web.UI.XslControlRenderingType, Sitecore.Kernel" propertyMap="Path=path" /> <control template="webcontrol" type="Sitecore.Web.UI.WebControlRenderingType, Sitecore.Kernel" propertyMap="assembly=assembly, namespace=namespace, class=tag, properties=parameters" /> <control template="xmlcontrol" type="Sitecore.Web.UI.XmlControlRenderingType, Sitecore.Kernel" propertyMap="controlName=control name, properties=parameters" /> </renderingControls>
Now, each time you create a sublayout, it will automatically be able to use the VaryByCookie parameter, and vary the cache based on the contents of the cookie.
MORE TO READ:
- Sitecore caching – an overview by Jens Mikkelsen
- Customizing sublayout caching in Sitecore from Stackoverflow
- Basics of HTML Caching by Sitecore Basics
- Caching via Sitecore’s HTML Cache by Alan Gallauresi
