Skip to content

Instantly share code, notes, and snippets.

@seangwright
Last active March 9, 2021 20:01
Show Gist options
  • Save seangwright/7a373bcd158dec7ebf1c290618a2777d to your computer and use it in GitHub Desktop.
Save seangwright/7a373bcd158dec7ebf1c290618a2777d to your computer and use it in GitHub Desktop.
Collecting Cache Dependencies for layered caching in Xperience
public class ArticlesRepository : IArticlesRepository
{
private readonly ICacheDependenciesStore store;
public ArticlesRepository(ICacheDependenciesStore store)
{
this.store = store;
}
public IEnumerable<Article> GetAll(string nodeAliasPath)
{
store.Store(new[] { $"node|samplesite|{nodeAliasPath}|childnodes" });
// return the query results
}
}
public class CacheDependenciesStore : ICacheDependenciesStore, ICacheDependenciesScope
{
private readonly ConcurrentStack<HashSet<string>> keyScopes = new();
public void Begin() => keyScopes.Push(new HashSet<string>(StringComparer.OrdinalIgnoreCase));
public void Store(string[] keys)
{
if (!keyScopes.TryPeek(out var currentScope))
{
return;
}
foreach (string? key in keys)
{
currentScope.Add(key);
}
}
public IEnumerable<string> End()
{
if (!keyScopes.TryPop(out var currentScope))
{
return Enumerable.Empty<string>();
}
if (!keyScopes.TryPeek(out var parentScope))
{
return currentScope.AsEnumerable();
}
foreach (string? key in currentScope)
{
parentScope.Add(key);
}
return currentScope.AsEnumerable();
}
}
public class CoffeeRepository : ICoffeeRepository
{
private readonly ICacheDependenciesStore store;
public CoffeeRepository(ICacheDependenciesStore store)
{
this.store = store;
}
public IEnumerable<Coffee> GetBestSellers()
{
store.Store(new[] { $"nodes|samplesite|sample.coffee|all" });
// return the query results
}
}
@inject ICacheDependenciesScope Scope
@{ Scope.Begin(); }
<editable-area area-identifier="area1"
area-options-allowed-widgets="AreaRestrictionHelper.GetHomePageRestrictions()"
allow-widget-output-cache="true"
widget-output-cache-expires-sliding="TimeSpan.FromMinutes(5)"/>
#{ var keys = Scope.End().ToList(); } @* keys has all the dep keys of all widgets in the above editable area *@
<cache expires-after="TimeSpan.FromMinutes(1)">
Scope.Begin();
<vc:coffee-list />
<vc:locations-list />
<cache-dependency cache-keys="Scope.End().ToList()" />
@* the above CacheDependencyTagHelper has the correct keys for the ViewComponents that it wraps *@
</cache>
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<CacheDependenciesStore>();
services.AddScoped<ICacheDependenciesScope>(s => s.GetRequiredService<CacheDependenciesStore>());
services.AddScoped<ICacheDependenciesStore>(s => s.GetRequiredService<CacheDependenciesStore>());
// now, register other services that use the CacheDependenciesStore as scoped
}
public class WidgetViewComponent
{
private readonly IArticlesRepository articlesRepo,
private readonly ICoffeeRepository coffeeRepo,
private readonly ICacheDependenciesScope scope
public WidgetViewComponent(
IArticlesRepository articlesRepo,
ICoffeeRepository coffeeRepo,
ICacheDependenciesScope scope)
{
this.articlesRepo = articlesRepo;
this.coffeeRepo = coffeeRepo;
this.scope = scope;
}
public IViewComponentResult Invoke(ComponentViewModel vm, ICacheDependencies deps)
{
scope.Begin();
var articles = articlesRepo.GetAll(vm.Page.NodeAliasPath);
var bestSellers = coffeeRepo.GetBestSellers();
deps.CacheKeys = scope.End().ToList();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment