Caching news: Page builder widgets

   —   

Kentico Xperience 13 Refresh 1 brings a huge performance enhancement for ASP.NET Core MVC based widgets – caching of widget output.

A little bit of history

It has been a while since we introduced the page builder concept in MVC and the ability to build a page in a drag-and-drop fashion. While this was a great enhancement, especially for non-technical users, there were also some limitations when it came to performance and caching.

Sure, the implementation of a widget can leverage the CacheHelper API to optimize any data loads. Moreover, output caching can be used to limit the load times of pages enriched by the page builder. However, both of these optimizations have drawbacks that we wanted to address.

Caching the data loads within a widget improves database performance. However, the widget processing itself still has to be invoked by the system. Especially for widgets with very simple logic (and possibly no actual data loads), the processing overhead can be significant.

Caching the whole output of a page on the other hand is tricky to set up properly due to various dependencies of individual widgets, potentially multiplied by A/B testing variants and content personalization.

Widget output cache

The new support for widget output caching aims to address the typical hassles that come with widget caching. Widget authors can configure whether their widget is suitable for caching. They also provide cache dependencies for the cached output.

Developers of individual pages then get to decide, whether caching is enabled on a particular page and provide expiration details based on their caching strategy.

Last but not least, variants of widget output are cached with respect to A/B testing, content personalization and custom needs of widget developers.

Authoring a widget

Let’s see an example of how a widget author tells the system that their widget output is suitable for caching

[assembly: RegisterWidget("BannerWidget", typeof(BannerWidgetViewComponent), "Banner", typeof(BannerWidgetProperties), AllowCache = true)] // Note this flag public class BannerWidgetViewComponent : ViewComponent { // ...

If you take a closer look at the widget registration via the RegisterWidget attribute, you can see a new flag – AllowCache.

While the example depicts a widget based on a ViewComponent class, any widget can opt-in to allow output caching during its registration.

Specifying cache dependencies

Widgets often work with data that can become outdated. For instance if a marketer changes the banner text or image currently rendered in the banner widget, we want the system to flush the widget output cache and re-render the banner with the new text or image.

Similarly, we might have a widget with a list of the latest articles and we want to invalidate the output whenever a new article gets added.

In order to control the widget output cache dependencies, use the CacheDependencies property of the component view model. In the following example, we set its CacheKeys property to reflect the ID of the currently rendered banner

public ViewViewComponentResult Invoke(ComponentViewModel<BannerWidgetProperties> viewModel) { viewModel.CacheDependencies.CacheKeys = new List<string>() { $"my.banner|id|{properties.BannerId}" }; // ... }

If you are uncertain how to compose the cache keys for dependencies, see the reference in our documentation.

Also note that the system always adds a dependency on the page where the widget is rendered. When a content editor modifies a page via the Pages application, all the widgets on that page are re-rendered upon the next request.

Configuring a page builder page

As mentioned earlier in the article, the developers of pages are in charge of deciding whether and how to cache a particular page and its widgets.

Assuming you know how to create pages with editable areas, I will highlight the newly added options for cache configuration. Let’s say we want to use sliding expiration in our editable area

<editable-area area-identifier="area1" allow-widget-output-cache="true" widget-output-cache-expires-sliding="TimeSpan.FromMinutes(20)" />

By using the allow-widget-output-cache flag, we instruct the system to cache the output of widgets that support caching. The latter attribute decides how long the cache should last.

There are 3 options for controlling the cache duration

  • widget-output-cache-expires-sliding
  • widget-output-cache-expires-after
  • widget-output-cache-expires-on

If you prefer to render editable areas using the method invocation approach over the tag helper syntax, use the EditableAreaOptions class

@await Html.Kentico().EditableAreaAsync("area1", new EditableAreaOptions { AllowWidgetOutputCache = true, WidgetOutputCacheExpiresSliding = TimeSpan.FromMinutes(20) })

Summary

In order to improve performance of widget rendering in ASP.NET Core MVC projects, output caching support for page builder widgets was introduced.

When developing a widget, use the AllowCache property of the RegisterWidget attribute to indicate the widget is suitable for the output caching. By configuring the CacheDependencies property of the widget’s view component model, dependency cache keys can be explicitly controlled.

Moreover, upon rendering editable areas within a page, use the allow-widget-output-cache flag along with widget-output-cache-expires-[sliding|after|on] to enable the widget output cache and control the cache expiration.

 

In the next part, we will focus on varying the cache for widgets with multiple variants.

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.