Skip to content

Caching, Cache Dependencies, Async

Trevor Fayas edited this page Mar 10, 2022 · 2 revisions

Caching (both data and rendering) is an important step to optimizing your site's performance. It is also important to be able to clear caches when related data changes.

Tracking Dependencies

In order to track all dependencies that impact a given web section, the dependencies need to be stored and retrieved. The ICacheDependenciesScope.Begin() method starts tracking any dependencies that are added (using the ICacheDependenciesStore), and then when ICacheDependenciesScope.End() is called, an array of the dependencies is returned. This allows you to properly pass dependency keys to your <cache-dependency cache-keys=@CacheScope.End()/> parameter within a <cache></cache> tag.

Since most data retrieval occurs in the Controller/View Component, while the <cache></cache> tags are in the view, you often need to split your ICacheDependenciesStore.Begin() in your class, and call ICacheDependenciesStore.End() in the View.

Building Dependencies

YOU SHOULD ADD CACHE DEPENDENCIES ON ALL DATA RETRIEVAL OPERATIONS FROM THE API

The Baseline uses a custom class CacheDependencyKeysBuilder to easily add Cache Dependency Keys to the ICacheDependenciesStore. Each data retrieval function you call should create a new instance of this CacheDependencyKeysBuilder and add any dependencies applicable.

var builder = new CacheDependencyKeysBuilder(_siteRepository, _cacheDependenciesStore);
builder.PagePath(path, PathTypeEnum.Children);

Data caching also needs the same Dependency Keys when caching data calls (such as in the IPageRetriever or IProgressiveCache). You can pass the keys to these data functions from the CacheDependencyKeysBuilder as needed.

Passing Dependencies

For IPageRetriever, see this example from TabRepository.cs

var retriever = await _pageRetriever.RetrieveAsync<Tab>(
                query => query
                    .Path(path, PathTypeEnum.Children)
                    .Columns(new string[] {
                        nameof(Tab.DocumentID),
                        nameof(Tab.TabName)
                    })
                    .OrderBy(nameof(TreeNode.NodeLevel), nameof(TreeNode.NodeOrder)),
                cacheSettings => cacheSettings
                    .Dependencies((items, csbuilder) => builder.ApplyDependenciesTo(key => csbuilder.Custom(key)))
                    .Key($"GetTabsAsync|{path}")
                    .Expiration(TimeSpan.FromMinutes(60))
                );

For IProgressiveCache, see this example from BreadcrumbRepository.cs

_progressiveCache.Load(cs =>
            {
                if (cs.Cached)
                {
                    cs.CacheDependency = builder.GetCMSCacheDependency();
                }
                return new Breadcrumb()
                {
                    LinkText = ResHelper.LocalizeExpression("generic.default.breadcrumbtext"),
                    LinkUrl = ResHelper.LocalizeExpression("generic.default.breadcrumburl"),
                };
            }, new CacheSettings(1440, "GetDefaultBreadcrumb", _repoContext.CurrentCulture()))

For a Widget caching, you simply set the widgetProperties.CacheDependencies.CacheKeys = ICacheDependenciesStore.End(); to set the widget's cache dependencies.

Clone this wiki locally