Common Caching¶
Provide a small, shared caching abstraction with a default in-memory provider and optional persistent document storage providers.
Common.Caching provides the devkit's shared caching building block. It centers around the shared ICacheProvider contract from Common.Abstractions, ships the default IMemoryCache implementation, and offers fluent DI wiring that storage packages can extend with persistent cache providers.
The package is intentionally small. It gives other packages a consistent cache abstraction without forcing them to depend directly on IMemoryCache.
What It Provides¶
ICacheProvideras the shared cache contract.AddCaching()andWithInMemoryProvider()for DI registration.CachingBuilderContextas the fluent registration context.InMemoryCacheProviderConfigurationfor sliding and absolute expiration defaults.InMemoryCacheProvideras the default implementation.MemoryCacheExtensionsfor key enumeration and prefix-based invalidation.
Recommended Registration¶
Register caching during application startup, usually with settings from configuration:
builder.Services
.AddCaching(builder.Configuration)
.WithInMemoryProvider(new InMemoryCacheProviderConfiguration
{
SlidingExpiration = TimeSpan.FromMinutes(10)
});
If you omit the explicit configuration object, WithInMemoryProvider() will bind Caching:InProcess from configuration and fall back to a default InMemoryCacheProviderConfiguration.
AddCaching() also registers IMemoryCache if it is not already present.
Persistent Caching With Document Storage¶
If you need cache entries to survive process restarts or be shared across multiple hosts, switch the cache provider to a document storage backed implementation.
For Entity Framework-backed persistence:
builder.Services
.AddCaching(builder.Configuration)
.WithEntityFrameworkDocumentStoreProvider<AppDbContext>(
new DocumentStoreCacheProviderConfiguration
{
SlidingExpiration = TimeSpan.FromMinutes(20),
AbsoluteExpiration = DateTimeOffset.UtcNow.AddHours(6)
});
This registration:
- stores cache entries as
CacheDocumentrecords in the document store, - registers an
IDocumentStoreClient<CacheDocument>automatically, - uses the
Caching:DocumentStoreconfiguration section by default, and - requires
AppDbContextto implementIDocumentStoreContextso the document-store table is part of the consuming application's schema.
If you already provide your own IDocumentStoreClient<CacheDocument> plus an IDistributedCache, you can register the cache abstraction directly with:
builder.Services
.AddCaching(builder.Configuration)
.UseDocumentStoreProvider();
The storage packages also expose provider-specific persistent registrations such as:
WithEntityFrameworkDocumentStoreProvider<TContext>()WithCosmosDocumentStoreProvider(...)WithAzureBlobDocumentStoreProvider(...)WithAzureTableDocumentStoreProvider(...)
How To Use It¶
Use the provider for simple read-through caching, lookup tables, and invalidation patterns:
public class CustomerCacheService(ICacheProvider cache)
{
public async Task<CustomerModel> GetAsync(string key, CancellationToken cancellationToken)
{
if (await cache.TryGetAsync(key, out CustomerModel value, cancellationToken))
{
return value;
}
value = await LoadCustomerAsync(cancellationToken);
await cache.SetAsync(key, value, slidingExpiration: TimeSpan.FromMinutes(5), cancellationToken: cancellationToken);
return value;
}
}
The provider exposes the expected cache operations:
GetandGetAsyncTryGetandTryGetAsyncSetandSetAsyncRemoveandRemoveAsyncRemoveStartsWithandRemoveStartsWithAsyncGetKeysandGetKeysAsync
Prefix-based keys work especially well with RemoveStartsWith(), so a stable key naming convention is important.
Integration Points¶
DocumentStorageuses cache behaviors to speed up repeated reads.DocumentStoragecan also backICacheProvideritself throughDocumentStoreCacheProvider, which enables persistent cache entries over EF, Cosmos DB, Azure Blob Storage, or Azure Table Storage.Requester and Notifieruse cache invalidation behaviors for request-driven workflows.ADRsaround service lifetimes and dependency injection reference caching as a shared infrastructure concern. See ADR-0018: Dependency Injection Service Lifetimes.
Caveats¶
Common.Cachingitself only ships the in-memory provider. Persistent cache providers come from the storage packages and must be registered explicitly.MemoryCacheExtensions.GetKeys()and the prefix helpers inspectMemoryCacheinternals. They are useful operational helpers, but they are not the same kind of stable contract asICacheProvideritself.LoggingCacheProviderBehaviorcurrently exists in the codebase, but its members throwNotImplementedException. Do not treat it as a supported production decorator yet.- Cache keys should be explicit and predictable. The invalidation helpers are most effective when keys share a clear prefix per feature or aggregate.