Is this really the version you are looking for? Kentico Xperience 12 Service Pack Documentation is no longer updated. Use the switcher in the header to choose your product version.
When using ASP.NET output caching (opens in a new tab) to improve the performance of your MVC website, you need to take additional steps to ensure that the output cache correctly stores personalized pages. Because personalized pages serve different content based on various conditions, you need to adjust your application to cache separate output versions according to the personalization criteria.
To cache different versions of content, use the OutputCache (opens in a new tab) attribute together with a custom implementation of the GetVaryByCustomString (opens in a new tab) method.
Kentico offers a fluent API built around .NET framework's VaryByCustomString output caching feature that allows you to construct output cache keys according to your project's caching requirements. The system provides an IOutputCacheKeyOptions interface that allows you to create configurable objects for building output cache keys. The options object is configured by chaining any number of VaryBy methods (representing cache key parts). The complete cache key is then constructed by calling OutputCacheKeyHelper.GetVaryByCustomString with the options object as the parameter.
By default, the system allows you to construct the cache key using the following request variables (extension methods for IOutputCacheKeyOptions objects):
Method | Namespace | Cache key |
|---|---|---|
VaryByBrowser | Kentico.Web.Mvc | The name and the major version of the client's browser. |
VaryByHost | Kentico.Web.Mvc | The host (opens in a new tab) name of the server. |
VaryBySite | Kentico.Web.Mvc | The code name of the site. |
VaryByUser | Kentico.Web.Mvc | The name of the current user. |
VaryByCookieLevel | Kentico.Web.Mvc | The cookie level of the current user. |
VaryByPersona | Kentico.OnlineMarketing.Web.Mvc | |
VaryByABTestVariant | Kentico.OnlineMarketing.Web.Mvc | The GUID of the A/B test variant assigned for the current request. |
The following steps describe how to cache multiple versions of personalized output using custom strings:
Edit your project's Global.asax.cs file and override the GetVaryByCustomString (opens in a new tab) method.
The method's custom parameter contains the string that you set in the VaryByCustom property of OutputCache attributes in your controllers.
For each custom string, you need to define the caching requirements – use VaryBy methods on an IOutputCacheKeyOptions object to create a set of request variables according to which the output cache needs to vary.
using System;
using System.Web;
using Kentico.Web.Mvc;
using Kentico.OnlineMarketing.Web.Mvc;public override string GetVaryByCustomString(HttpContext context, string custom)
{
// Creates the options object used to store individual cache key parts
IOutputCacheKeyOptions options = OutputCacheKeyHelper.CreateOptions();
// Selects a caching configuration according to the current custom string
switch (custom)
{
case "Default":
// Sets the variables that compose the cache key for the 'Default' VaryByCustom string
options
.VaryByHost()
.VaryByBrowser()
.VaryByUser();
break;
case "OnlineMarketing":
// Sets the variables that compose the cache key for the 'OnlineMarketing' VaryByCustom string
options
.VaryByCookieLevel()
.VaryByPersona()
.VaryByABTestVariant();
break;
}
// Combines individual 'VaryBy' key parts into a cache key under which the output is cached
string cacheKey = OutputCacheKeyHelper.GetVaryByCustomString(context, custom, options);
// Returns the constructed cache key
if (!String.IsNullOrEmpty(cacheKey))
{
return cacheKey;
}
// Calls the base implementation if the provided custom string does not match any predefined configurations
return base.GetVaryByCustomString(context, custom);
}Important
The cache keys created in the example above ensure caching for a broad range of variables contained within each request. This may be unnecessary for your website. For optimal caching, you need to prepare output cache variables tailored according to personalization conditions that you use on the site or individual pages.
For example, pages that check for contact personas in their personalization condition only require the persona identifier in the cache variables, and you can share the cached content for other variables, such as contact groups to which the contacts belong. On the other hand, strongly personalized pages with dynamic content may require separate cache versions for every contact.
You always need to balance website performance, memory usage on the server, and the risk of displaying incorrect cached content.
Edit the controller classes that serve personalized content on your MVC site.
Set the VaryByCustom property of OutputCache attributes to one of the specified configurations according to the action's caching requirements.
using System.Web.Mvc;
using CMS.ContactManagement;
using LearningKit.Models.Personalization;
namespace LearningKit.Controllers
{
public class PersonalizationController : Controller
{
/// <summary>
/// Gets the current contact, if contact tracking is enabled for the connected Kentico instance.
/// </summary>
private ContactInfo CurrentContact => ContactManagementContext.GetCurrentContact();
/// <summary>
/// Displays a page with a personalized greeting.
/// The content depends on whether the current contact belongs to the "YoungCustomers" persona.
/// Caches the output for 10 minutes, with different cache versions defined by the "OnlineMarketing" custom string.
/// The "OnlineMarketing" configuration separately caches each combination of persona and AB test variant variables.
/// </summary>
[OutputCache(Duration = 600, VaryByCustom = "OnlineMarketing")]
public ActionResult PersonalizedGreeting()
{
CurrentContactViewModel model;
// If on-line marketing is disabled, CurrentContact is null
if (CurrentContact != null)
{
model = new CurrentContactViewModel(CurrentContact);
}
else
{
model = null;
}
return View(model);
}
}
}The application now caches separate versions of action output based on your custom variables. This ensures that visitors do not receive incorrect cached content when viewing personalized pages.
In addition to the cache variables provided by the system, you can vary the cache key based on any accessible request variable.
There are two ways to extend the general support provided by Kentico:
You can extend the provided support by implementing additional cache key parts for IOutputCacheKeyOptions. This approach allows for easy reusability of the implemented methods across multiple projects.
Cache key parts consist of:
The following sample demonstrates the implementation of a cache key that varies cached content based on a contact's gender.
using System.Web;
using CMS.ContactManagement;
using Kentico.Web.Mvc;
namespace OutputCacheCustomization
{
public class ContactGenderOutputCacheKey : IOutputCacheKey
{
// Used as a prefix for this cache key part
public string Name => "KenticoContactGender";
// Invoked when constructing a cache key from the configured 'IOutputCacheKeyOptions' options object
public string GetVaryByCustomString(HttpContextBase context, string custom)
{
// Gets the current contact, without creating a new anonymous contact for new visitors
ContactInfo existingContact = ContactManagementContext.GetCurrentContact(createAnonymous: false);
// Gets the contact's gender
int? contactGender = existingContact?.ContactGender;
return $"{Name}={contactGender}";
}
}
}Create a corresponding extension method for IOutputCacheKeyOptions. The method adds an instance of the class to an IOutputCacheKeyOptions object using the AddCacheKeymethod.
using Kentico.Web.Mvc;
namespace OutputCacheCustomization
{
public static class OutputCacheKeyOptionsExtensions
{
// Varies the output cache based on the contact's gender
public static IOutputCacheKeyOptions VaryByContactGender(this IOutputCacheKeyOptions options)
{
// Adds the ContactGenderOutputCacheKey to the options object
options.AddCacheKey(new ContactGenderOutputCacheKey());
return options;
}
}
}You can now use the ContactGender variable when building cache keys in the site's GetVaryByCustomString implementation.
An alternative approach to implementing reusable extension methods is constructing the cache key using OutputCacheKeyHelper.GetVaryByCustomString and further customizing it by directly appending additional request variables.
The following example implements a custom GetContactGroupsCacheKey method that returns a semicolon-separated list of all contact groups to which the current contact belongs. The string is appended to the cache key constructed by the GetVaryByCustomString helper method, adding another level of variance to the output cache.
private string GetContactGroupsCacheKey()
{
// Gets the current contact without creating a new anonymous contact for new visitors
var existingContact = ContactManagementContext.GetCurrentContact(createAnonymous: false);
if (existingContact == null)
{
return String.Empty;
}
// Gets the contact groups assigned to the contact
var groups = existingContact.ContactGroups?.Select(x => x.ContactGroupID).OrderBy(x => x).ToArray() ?? new int[] { };
// Creates a string used to vary the resulting cache key
var groupsKey = String.Join(";", groups);
return $"ContactGroups={groupsKey}";
}
public override string GetVaryByCustomString(HttpContext context, string custom)
{
// The configuration of the 'IOutputCacheKeyOptions' object is omitted
...
// Combines individual 'VaryBy' components into a cache key under which the output is cached
string cacheKey = OutputCacheKeyHelper.GetVaryByCustomString(context, custom, options);
// Prepares an empty string object for the contact groups key part
string contactGroupsKey = String.Empty;
// Checks if the current request requires caching based on contact groups
// As an example, we use contact group caching for the 'OnlineMarketing' configuration
if (String.Equals(custom, "OnlineMarketing", StringComparison.InvariantCultureIgnoreCase))
{
contactGroupsKey = GetContactGroupsCacheKey();
}
// Appends the contact groups string to the end of the constructed cache key
// Separates the key part using the pipe '|' character - a separator used internally
// for all cache key parts by the 'OutputCacheKeyHelper.GetVaryByCustomString' method
if (!String.IsNullOrEmpty(contactGroupsKey))
{
cacheKey = String.Join("|", cacheKey, contactGroupsKey);
}
// Returns the constructed cache key
if (!String.IsNullOrEmpty(cacheKey))
{
return cacheKey;
}
// Calls the base implementation if the provided custom string does not match any predefined configuration
return base.GetVaryByCustomString(context, custom);
}