Caching news: Page builder widgets, part II


The first part of the article series dedicated to page builder widgets focused on how to enable caching in general, configure the cache expiration and control the dependencies of cached output.

In this article, I will go into detail about varying the cache content to accommodate some advanced scenarios.

Vary by options

Sometimes, widgets have content which is tailored for a particular group of visitors or for a specific visitor only. Let’s assume we want to create a widget for greeting users, which incorporates the user’s name in its content. We definitely do not want such a widget to be cached only once and displayed to all users with the same content (i.e. with the same name in the greeting).

What we want is to maintain variants of the cached output where each user is served their own content. That is where the CacheVaryBy attribute comes into play. By decorating the view component class of a widget using this attribute, the widget developer has control over how the cached content varies. See the following snippet

[CacheVaryBy(VaryByUser = true)] public class GreetingWidgetViewComponent : ViewComponent { public ViewViewComponentResult Invoke() { var name = HttpContext.User.Identity.Name; return View("~/Components/Widgets/GreetingWidget/_GreetingWidget.cshtml", name); } }

When invoking the greeting widget, we pass the user’s name as the model to the view in order to render a personalized greeting.

And to make sure every user sees their own name, not the name which first gets cached, we set the VaryByUser flag using the CacheVaryBy attribute.

There are several properties of the attribute which allow us to fine tune the cache behavior

  • VaryByCookie
  • VaryByCookieLevel
  • VaryByCulture
  • VaryByHeader
  • VaryByHost
  • VaryByQuery
  • VaryByRoute
  • VaryByUser

The VaryByCulture flag is set to true by default.

Personalizing widgets and A/B testing

Xperience offers out-of-the-box support for optimizing pages based on the page builder using A/B testing. From the caching perspective, this is another varying option the caching mechanism has to reflect in order to properly display A/B test variants to site visitors.

Since A/B testing is a native feature of the system, widget developers do not need to worry about variants. Widget output cache content automatically varies according to the selected A/B test page variant.

Similarly, there is embedded support for personalizing widgets, which allows displaying of specific content based on conditions. When caching, Xperience automatically varies the cached widget output based on the personalization variant, regardless of the used condition. No further action is needed from the developer’s standpoint.

Custom vary by options

While we tried to cater for all typical scenarios developers run into when varying the cache contents, there is also a mechanism to introduce custom options for varying the cache.

Implementing custom options

To provide a custom key to vary the cache by, start by implementing the ICacheVaryByOption interface. The GetKey() method needs to return a key uniquely identifying both the type of the option and the rendered variant of the widget’s content.

To demonstrate how to implement such an option, I am adding an excerpt from the existing VaryByCookieLevel option

public class VaryByCookieLevel : ICacheVaryByOption { // Specify dependencies of the option public VaryByCookieLevel(ICurrentCookieLevelProvider currentCookieLevelProvider) { this.currentCookieLevelProvider = currentCookieLevelProvider; } // Decide on the key public string GetKey() { return $"CookieLevel={currentCookieLevelProvider.GetCurrentCookieLevel()}"; }

The constructor can specify dependencies that the option uses to determine the key. In our case, we depend on the cookie level provider.

Using custom options

One last thing remains to be answered – how to use custom varying options? The already mentioned CacheVaryBy attribute accepts types of options to apply. These can be combined with the native flags of the attribute

// Just for illustration, the VaryByCookieLevel flag can be used instead [CacheVaryBy(typeof(VaryByCookieLevel))] public class GreetingWidgetViewComponent : ViewComponent { // ...


Widget developers can decide how the content of a widget varies in the cache. Using the Kentico.PageBuilder.Web.Mvc.CacheVaryBy attribute, several out-of-the-box options can be set.

The system automatically varies the cached output for widget variants created by the system’s built-in features (A/B testing of pages and widget personalization). Moreover, every culture has its own cache variant by default.

Should you need a custom vary by option, implement the Kentico.PageBuilder.Web.Mvc.ICacheVaryByOption interface and decorate the widget view component by passing the option to the CacheVaryBy attribute: [CacheVaryBy(typeof(MyVaryByOption))].

Share this article on   LinkedIn

Marek Fesar

Hi, I am the Principal Technical Leader here at Kentico and I primarily focus on the design, architecture and core of our solution.