Skip to content

Caching

The caching module provides the Suite-level cache abstraction for application and service code. Prefer this API over using ASP.NET HybridCache or IDistributedCache directly so cache keys, provider behavior, and tests stay consistent across features.

Module setup

Add the module dependency from the Suite module that owns the cached feature:

C#
1
2
3
4
5
6
public override void SetupModule(IModuleBuilder builder)
{
    base.SetupModule(builder);

    builder.DependsOn<CachingModule>();
}

CachingModule depends on the environment and Redis modules. When the application is configured with Redis, the distributed cache layer is backed by Redis.

Cache API

The module exposes ISuiteHybridCache, a Suite wrapper over ASP.NET HybridCache. Use it for feature caches that need normalized Suite keys, cache tags, factory coalescing, and optional local-memory plus distributed layers.

Use SuiteHybridCacheEntryOptions { UseLocalCache = false } when a feature needs distributed-only behavior. This still uses the distributed cache provider, but avoids another in-process copy of the cached value.

The API uses SuiteCacheKey instead of raw strings. A key has a scope owned by the feature and a name owned by the entry:

C#
var key = new SuiteCacheKey("SharingLevels", "EntitySharingKey");

Keys are normalized before reaching the cache provider. By default the final key includes the optional cache prefix, current installation id, application name, scope, and name. Segments are normalized to lower kebab-case, and invalid keys are rejected. For example, EntitySharingKey is normalized to entity-sharing-key.

CachingModuleOptions controls the cross-cutting key behavior:

  • KeyPrefix prepends a fixed prefix to every key.
  • IncludeCurrentInstallationId includes the current installation id by default.
  • IncludeApplicationName includes the entry assembly name by default.
  • HybridLocalCacheExpirationInSeconds controls the default local-memory expiration for hybrid cache entries. The default is 30 seconds.

Only disable the installation id or application name when the cached data is intentionally shared across those boundaries.

Cache options

Use SuiteHybridCacheEntryOptions to choose which cache layers participate:

C#
await this.cache.GetOrCreateAsync(
    new SuiteCacheKey("Inventory", "LookupById"),
    ct => this.LoadLookupAsync(ct),
    new SuiteHybridCacheEntryOptions
    {
        Expiration = TimeSpan.FromMinutes(10),
        LocalCacheExpiration = TimeSpan.FromSeconds(30),
        UseLocalCache = true,
        UseDistributedCache = true,
    },
    cancellationToken: cancellationToken);

Set UseLocalCache = false for memory-sensitive paths, high-cardinality data, or features that already own a separate memoization layer. The entry will still use the distributed layer when UseDistributedCache remains enabled.

Use cache tags when a feature needs group invalidation:

C#
await this.cache.RemoveByTagAsync("inventory-lookups", cancellationToken);

ASP.NET HybridCache owns cache serialization. Feature code should pass typed values to ISuiteHybridCache and avoid manual serialization around cache entries.

Testing

Use ITsynch.Suite.CachingModule.Testing in tests that need a lightweight distributed cache:

  • TestDistributedCache is an in-memory IDistributedCache implementation.
  • CountingDistributedCache records async get and set calls for assertions.

Performance-oriented service tests can also use BasePerformanceIntegrationTest<>.ConfigureCountingDistributedCache to collect distributed-cache counters in the performance report.