There are lots of good quality Blog and Forum posts about differing ways to implement Block level Donut style Output caching in Optimizely.
The below is the approach I prefer to use. It keeps things simple while making sure that cache is unique for visitor groups and languages. Using this method cache will also be invalidated when a new version of a block is published.
Block controller
Add the Output Cache attribute to the Block Controller index method.
[OutputCache(VaryByParam = "currentBlock", VaryByCustom = "language", Duration = 600)]
public ActionResult Index(ProductListBlock currentBlock)
VaryByParam: Setting this to “currentBlock” will cache based on the ToString() method of the BlockData model returning the cache key. We add our logic there to make sure cache is refreshed appropriately.
VaryByCustom: Used to extend output caching with custom requirements. You must handle logic for the custom string by overriding the GetVaryByCustomString method in the Global.asax. We use this to cache language specific versions of our block.
Block Model
Override the Block model ToString() method to return unique cache keys for published versions of the block.
public override string ToString()
{
var content = this as IContent;
var changeTrackable = this as IChangeTrackable;
if (content != null && changeTrackable != null)
return $"{content.ContentGuid}-{changeTrackable.Saved.Ticks}-{EPiServer.Editor.PageEditing.PageIsInEditMode}";
return base.ToString();
}
Global.asax
Override the GetVaryByCustomString method in the Global.asax for the custom string passed into the OutputCache declaration. In our case this makes sure that language versions of the block are uniquely cached.
public override string GetVaryByCustomString(HttpContext context, string custom)
{
if (custom == "language")
{
return HttpContext.Current.Request.Cookies["Language"]?.ToString();
}
return base.GetVaryByCustomString(context, custom);
}
Interesting way of handling the block cache. Nice job Johnny
LikeLike
Thanks Vincent! Although I can’t take a lot of credit as good content is already out there in blog and forum posts. I just tried a few approaches, decided what worked best for me and shared. Hope you are keeping well mate!
LikeLike
Yeah this is way I’ve handled it for a long time. Although I’ve crafted a framework to add cache dependencies through the ISynchronizedCache system so that the strings are also based upon any ContentAreas and ContentReferences/PageReferences as the one limitation with this is it ONLY works with it’s own content.
LikeLike
That’s an excellent idea Scott. Really interested in learning more about how you integrated this approach with ISynchronizedCache.
LikeLike
Sure I can grab you sometime and show you what I’ve done. Sadly as we’re all done I created a framework for an old agency I lost access to but I have a POC that I created for one of our teams that used it and built on it. Can show you the idea. Should probably blog about it sometime too :p The one thing recently on my radar is I don’t know if this works with .NET 5, I was told by some of our devs the caching doesn’t work the same they don’t think but have to look in to it
LikeLike
Sounds good Scott 🙂 Yes the .Net 5 move is scary as there are so many seemingly small things like this that may require rework. But it’s much more exciting than it is scary. I can’t wait!
LikeLike