![]() |
VOOZH | about |
dotnet add package Rystem.RepositoryFramework.Cache --version 10.0.8
NuGet\Install-Package Rystem.RepositoryFramework.Cache -Version 10.0.8
<PackageReference Include="Rystem.RepositoryFramework.Cache" Version="10.0.8" />
<PackageVersion Include="Rystem.RepositoryFramework.Cache" Version="10.0.8" />Directory.Packages.props
<PackageReference Include="Rystem.RepositoryFramework.Cache" />Project file
paket add Rystem.RepositoryFramework.Cache --version 10.0.8
#r "nuget: Rystem.RepositoryFramework.Cache, 10.0.8"
#:package Rystem.RepositoryFramework.Cache@10.0.8
#addin nuget:?package=Rystem.RepositoryFramework.Cache&version=10.0.8Install as a Cake Addin
#tool nuget:?package=Rystem.RepositoryFramework.Cache&version=10.0.8Install as a Cake Tool
Rystem.RepositoryFramework.Cache adds cache decorators on top of Repository Framework registrations. You keep resolving the same IRepository<T, TKey>, IQuery<T, TKey>, or ICommand<T, TKey> services, but the runtime pipeline first checks a cache layer and then falls back to the original storage implementation.
The package is intentionally thin: it does not replace your storage, it decorates it.
dotnet add package Rystem.RepositoryFramework.Cache
The package registers one of these decorators:
CachedRepository<T, TKey> for full repositories.CachedQuery<T, TKey> for query-only registrations.CachedRepository<T, TKey> for command-only registrations, but only when cache options include write methods.That means caching is opt-in per registration and per method group.
builder.Services.AddRepository<Country, CountryKey>(repositoryBuilder =>
{
repositoryBuilder.WithInMemory(builder =>
{
builder.PopulateWithRandomData(100, 100);
});
repositoryBuilder.WithInMemoryCache(cache =>
{
cache.ExpiringTime = TimeSpan.FromSeconds(10);
cache.Methods = RepositoryMethods.Get
| RepositoryMethods.Query
| RepositoryMethods.Exist;
});
});
After registration, the resolved IRepository<Country, CountryKey> behaves like this:
WithInMemoryCache(...)Uses the package-provided InMemoryCache<T, TKey> over IMemoryCache.
AddMemoryCache() automatically.Singleton.builder.Services.AddRepository<Plant, int>(repositoryBuilder =>
{
repositoryBuilder.WithInMemory();
repositoryBuilder.WithInMemoryCache(cache =>
{
cache.ExpiringTime = TimeSpan.FromMinutes(1);
cache.Methods = RepositoryMethods.Query | RepositoryMethods.Get;
});
});
WithDistributedCache(...)Wraps the Microsoft.Extensions.Caching.Distributed.IDistributedCache that is already in DI.
AbsoluteExpiration, AbsoluteExpirationRelativeToNow, and SlidingExpiration to the same ExpiringTime.Singleton by default.builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = builder.Configuration.GetConnectionString("Redis");
options.InstanceName = "RepositoryFramework";
});
builder.Services.AddRepository<Country, CountryKey>(repositoryBuilder =>
{
repositoryBuilder.WithInMemory(builder =>
{
builder.PopulateWithRandomData(100, 100);
});
repositoryBuilder.WithDistributedCache(cache =>
{
cache.ExpiringTime = TimeSpan.FromSeconds(10);
cache.Methods = RepositoryMethods.Query | RepositoryMethods.Get | RepositoryMethods.Exist;
});
});
WithCache<T, TKey, TCache>(...)Use this when you want a custom in-process or custom remote cache implementation.
public sealed class MyCache<T, TKey> : ICache<T, TKey>
where TKey : notnull
{
public Task<CacheResponse<TValue>> RetrieveAsync<TValue>(
string key,
CancellationToken cancellationToken = default)
=> Task.FromResult(new CacheResponse<TValue>(false, default));
public Task<bool> SetAsync<TValue>(
string key,
TValue value,
CacheOptions<T, TKey> options,
CancellationToken? cancellationToken = null)
=> Task.FromResult(true);
public Task<bool> DeleteAsync(
string key,
CancellationToken cancellationToken = default)
=> Task.FromResult(true);
}
builder.Services.AddRepository<Plant, int>(repositoryBuilder =>
{
repositoryBuilder.WithInMemory();
repositoryBuilder.WithCache<Plant, int, MyCache<Plant, int>>(cache =>
{
cache.ExpiringTime = TimeSpan.FromMinutes(5);
cache.Methods = RepositoryMethods.All;
});
});
WithDistributedCache<T, TKey, TCache>(...)Use this when your custom cache should be treated as a distributed cache layer.
TCache must implement IDistributedCache<T, TKey>, which extends ICache<T, TKey>.
The cache package works on full repositories and on CQRS-only registrations.
builder.Services.AddQuery<Plant, int>(queryBuilder =>
{
queryBuilder.WithInMemory();
queryBuilder.WithInMemoryCache(cache =>
{
cache.ExpiringTime = TimeSpan.FromMinutes(5);
});
});
For command-only registrations, the decorator is added only when you cache write methods.
builder.Services.AddCommand<Plant, int>(commandBuilder =>
{
commandBuilder.WithInMemory();
commandBuilder.WithInMemoryCache(cache =>
{
cache.ExpiringTime = TimeSpan.FromMinutes(1);
cache.Methods = RepositoryMethods.Insert
| RepositoryMethods.Update
| RepositoryMethods.Delete;
});
});
If you configure only Get, Query, or Exist on a command registration, there is no command decorator to apply those settings.
The decorators support having both local and distributed cache layers on the same registration. The unit tests wire exactly that pattern with in-memory storage plus in-memory cache plus Redis-backed distributed cache.
builder.Services.AddRepository<Country, CountryKey>(repositoryBuilder =>
{
repositoryBuilder.WithInMemory(builder =>
{
builder.PopulateWithRandomData(100, 100);
});
repositoryBuilder
.WithInMemoryCache(cache =>
{
cache.ExpiringTime = TimeSpan.FromSeconds(10);
})
.WithDistributedCache(cache =>
{
cache.ExpiringTime = TimeSpan.FromSeconds(10);
});
});
Read flow in that setup:
ICache<T, TKey>IDistributedCache<T, TKey>GetAsync(key) caches the returned model.ExistAsync(key) caches the returned State<T, TKey>.QueryAsync(filter) materializes the full async stream to a List<Entity<T, TKey>> and caches that list.OperationAsync(...) is also cached, and it uses the Query flag to decide whether caching is enabled.Because query results are materialized before caching, this package is best for repeated reads of the same filter, not for preserving streaming behavior end-to-end.
InsertAsync can refresh Get and Exist cache entries for the affected key.UpdateAsync can refresh Get and Exist cache entries for the affected key.DeleteAsync can remove Get and Exist cache entries for the affected key.BatchAsync updates or removes per-key Get and Exist entries as it iterates through batch results.The package does not keep a registry of query filters, so write operations do not invalidate previously cached query results.
That behavior is visible in RepositoryFramework.UnitTest/Tests/Cache/CacheTest.cs: deleting all records from the underlying repository does not remove the cached query result, so the old list is served again until cache expiration.
The decorators build their own cache keys.
Get and Exist include method name, model type name, factory name, and serialized key.Query includes method name, model type name, and the filter key.Operation includes method name, operation name, model type name, and the filter key.Practical consequence:
Get and ExistIf you use multiple named registrations for the same model with different backends, document that behavior for your team before enabling query caching.
CacheOptions<T, TKey>| Property | Default | Notes |
|---|---|---|
Methods |
Query | Get | Exist |
Controls which operations participate in caching. |
ExpiringTime |
365 days |
Used by the built-in in-memory cache and passed to custom caches. |
HasCommandPattern becomes true when Methods includes Insert, Update, Delete, or All.
DistributedCacheOptions<T, TKey>Inherits from CacheOptions<T, TKey>.
| Property | Default | Notes |
|---|---|---|
Methods |
Query | Get | Exist |
Same behavior as CacheOptions<T, TKey>. |
ExpiringTime |
365 * 365 days |
Very large default; set it explicitly for real workloads. |
RepositoryMethods flags in cache scenarios| Flag | Effect |
|---|---|
Get |
Enables read-through caching for GetAsync. |
Exist |
Enables read-through caching for ExistAsync. |
Query |
Enables caching for QueryAsync and OperationAsync. |
Insert |
After insert, refreshes key-based cache entries. |
Update |
After update, refreshes key-based cache entries. |
Delete |
After delete, removes key-based cache entries. |
All |
Enables every flag. |
The cache package does not add its own bootstrap workflow. Any warm-up still comes from the underlying repository registration, for example when an in-memory repository is populated through PopulateWithRandomData(...) and then activated via WarmUpAsync().
Use it when you want to:
If you also need a Blob Storage-backed distributed cache provider, see ../RepositoryFramework.Cache.Azure.Storage.Blob/README.md.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
Showing the top 1 NuGet packages that depend on Rystem.RepositoryFramework.Cache:
| Package | Downloads |
|---|---|
|
Rystem.RepositoryFramework.Cache.Azure.Storage.Blob
Rystem.RepositoryFramework allows you to use correctly concepts like repository pattern, CQRS and DDD. You have interfaces for your domains, auto-generated api, auto-generated HttpClient to simplify connection "api to front-end", a functionality for auto-population in memory of your models, a functionality to simulate exceptions and waiting time from external sources to improve your implementation/business test and load test. |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 10.0.8 | 5,578 | 5/13/2026 |
| 10.0.7 | 176 | 3/26/2026 |
| 10.0.6 | 433,697 | 3/3/2026 |
| 10.0.5 | 211 | 2/22/2026 |
| 10.0.4 | 214 | 2/9/2026 |
| 10.0.3 | 147,988 | 1/28/2026 |
| 10.0.1 | 209,413 | 11/12/2025 |
| 9.1.3 | 347 | 9/2/2025 |
| 9.1.2 | 764,869 | 5/29/2025 |
| 9.1.1 | 97,957 | 5/2/2025 |
| 9.0.32 | 186,775 | 4/15/2025 |
| 9.0.31 | 5,848 | 4/2/2025 |
| 9.0.30 | 88,845 | 3/26/2025 |
| 9.0.29 | 9,059 | 3/18/2025 |
| 9.0.28 | 314 | 3/17/2025 |
| 9.0.27 | 295 | 3/16/2025 |
| 9.0.26 | 316 | 3/13/2025 |
| 9.0.25 | 52,174 | 3/9/2025 |
| 9.0.21 | 792 | 3/6/2025 |
| 9.0.20 | 19,633 | 3/6/2025 |