Space.Modules.InMemoryCache
1.4.0
dotnet add package Space.Modules.InMemoryCache --version 1.4.0
NuGet\Install-Package Space.Modules.InMemoryCache -Version 1.4.0
<PackageReference Include="Space.Modules.InMemoryCache" Version="1.4.0" />
<PackageVersion Include="Space.Modules.InMemoryCache" Version="1.4.0" />
<PackageReference Include="Space.Modules.InMemoryCache" />
paket add Space.Modules.InMemoryCache --version 1.4.0
#r "nuget: Space.Modules.InMemoryCache, 1.4.0"
#:package Space.Modules.InMemoryCache@1.4.0
#addin nuget:?package=Space.Modules.InMemoryCache&version=1.4.0
#tool nuget:?package=Space.Modules.InMemoryCache&version=1.4.0
Space.Modules.InMemoryCache
In-memory cache module for the Space framework. Adds a caching layer in the handler pipeline when a method is annotated.
Status & Packages
CI | Branch | Status |
---|---|---|
Prod (Stable Publish) | master |
|
Dev (Preview Publish) | dev |
|
Validation (PR / Feature) | PRs → dev / master |
|
Coverage (Tests) | Release |
NuGet Packages
Package | Stable | Preview | Downloads | Description |
---|---|---|---|---|
Space.Modules.InMemoryCache | In-memory caching module + attribute integration |
NuGet
- Package page: https://www.nuget.org/packages/Space.Modules.InMemoryCache
- Target Frameworks: .NET 8
Install (stable):
dotnet add package Space.Modules.InMemoryCache
Install (preview):
dotnet add package Space.Modules.InMemoryCache --prerelease
Build & CI
- Prod CI (release pipeline): link
- Dev CI (dev branch): link
- Validation Build (feature branches & PRs): link
Coverage report is generated as
coverage.cobertura.xml
in CI (uploaded as artifact). You can wire Codecov/Coveralls later for a percentage badge if desired.
Registration
If the package is referenced, AddSpace()
will detect the module.
- Default provider registration
services.AddSpace();
services.AddSpaceInMemoryCache(); // registers InMemoryCacheModuleProvider
- Generic overload with a custom provider type
// Registers your own provider instead of the default
services.AddSpace();
services.AddSpaceInMemoryCache<MyCustomCacheProvider>();
- Generic overload + profile options
services.AddSpace();
services.AddSpaceInMemoryCache<MyCustomCacheProvider>(opt =>
{
// default profile used when attribute has no properties
opt.WithDefaultProfile(p => p.TimeSpan = TimeSpan.FromMinutes(1));
// named profile can be selected via [CacheModule(Profile = "fast")]
opt.WithProfile("fast", p => p.TimeSpan = TimeSpan.FromSeconds(5));
});
Order does not matter relative to AddSpace()
.
- Generic overload + profile options
services.AddSpace();
services.AddSpaceInMemoryCache<MyCustomCacheProvider>(opt =>
{
// default profile used when attribute has no properties
opt.WithDefaultProfile(p => p.TimeSpan = TimeSpan.FromMinutes(1));
// named profile can be selected via [CacheModule(Profile = "fast")]
opt.WithProfile("fast", p => p.TimeSpan = TimeSpan.FromSeconds(5));
});
Order does not matter relative to AddSpace()
.
Usage
Apply [CacheModule]
on a handler method (together with [Handle]
). The optional Duration
(seconds) influences the internal config TimeSpan
.
public class UserQueries
{
[Handle]
[CacheModule(Duration = 60)] // seconds
public ValueTask<List<UserDetail>> GetTopUsers(HandlerContext<int> ctx)
{
// access services via ctx.ServiceProvider
// return cached value if present (module manages this)
}
}
Manual Eviction (invalidate cached entries)
There are two ways to remove cached entries when your data mutates:
Remove a single key
- Use
ICacheModuleProvider
from your handler/command. - Build the cache key of the related query using
GetKey(request)
and callRemove(key)
.
- Use
Clear all cache entries
- Call
Clear()
on the provider (useful for admin/ops or wide reconfiguration).
- Call
Example: invalidate a cached query after a successful mutation
public record GetUser(string Email) : IRequest<UserDto>;
public record UpdateUser(string Email, string NewId) : IRequest<Nothing>;
public class UserQueries
{
[Handle]
[CacheModule(Duration = 60)]
public ValueTask<UserDto> Get(HandlerContext<GetUser> ctx)
=> ValueTask.FromResult(new UserDto($"{ctx.Request.Email}:{Guid.NewGuid()}"));
}
public class UserCommands(ICacheModuleProvider cache)
{
[Handle]
public ValueTask<Nothing> Update(HandlerContext<UpdateUser> ctx)
{
// do your state change first (DB/update etc.)
// ...
// then invalidate the related query cache
var key = cache.GetKey(new GetUser(ctx.Request.Email));
cache.Remove(key);
return ValueTask.FromResult(Nothing.Value);
}
}
Notes:
- Place eviction after a successful commit of the mutation.
- If multiple queries are affected, generate and remove all relevant keys.
Clear()
removes everything from the in-memory cache.
Key generation
By default the provider uses request.ToString()
as the cache key. For stable and readable keys, override ToString()
on your request records/DTOs (or implement a custom provider). Avoid GetHashCode()
for keys since hashes can collide and are not guaranteed to be stable across processes/versions.
How It Works
- Source generator detects
[CacheModule]
usage and prepares module metadata. - At runtime the module resolves an
ICacheModuleProvider
(default registered byAddSpaceInMemoryCache
). - The provider supplies keys and stores / retrieves values.
- Module order (
PipelineOrder = int.MinValue + 2
) ensures it runs before user pipelines but after any earlier system modules (e.g. Audit if introduced with lower order).
Custom Provider
Implement ICacheModuleProvider
to change key strategy or backing store (e.g. Redis):
public sealed class RedisCacheModuleProvider : ICacheModuleProvider
{
private readonly ConcurrentDictionary<string, object> store = new();
public string GetKey<TRequest>(TRequest request) => request?.ToString();
public ValueTask Store<TResponse>(string key, TResponse response, CacheModuleConfig cfg)
{ store[key] = response; return default; }
public bool TryGet<TResponse>(string key, out TResponse response, CacheModuleConfig cfg)
{
response = default;
if (!store.TryGetValue(key, out var obj)) return false;
response = (TResponse)obj; return true;
}
// optional manual eviction
public bool Remove(string key) => store.TryRemove(key, out _);
public void Clear() => store.Clear();
}
Register it using the DI extension:
services.AddSpaceInMemoryCache<RedisCacheModuleProvider>();
services.AddSpace();
Configuration Mapping
Duration
(int seconds) from the attribute populates CacheModuleConfig.TimeSpan
. If omitted or < 0 it is treated as 0 (no expiration). Global and named profile values can also provide TimeSpan
.
Breaking change
CacheModuleOptions
no longer exposesTimeSpan
. Configure TTL only via profiles usingWithDefaultProfile
/WithProfile
onCacheModuleOptions
withCacheProfileOptions
.- Any existing usage like
services.AddSpaceInMemoryCache(opt => opt.TimeSpan = ...)
must be replaced with:services.AddSpaceInMemoryCache(opt => { opt.WithDefaultProfile(p => p.TimeSpan = TimeSpan.FromMinutes(1)); // or named profiles opt.WithProfile("fast", p => p.TimeSpan = TimeSpan.FromSeconds(5)); });
- Provider hooks inherited from
BaseModuleOptions
(e.g.,WithModuleProvider
, provider action) are not consumed by this module. Provider resolution is: attributeProvider
→ DI-registeredICacheModuleProvider
→ built-inInMemoryCacheModuleProvider
.
Notes
- A module attribute augments its
[Handle]
method; it does not introduce its own method. - Only handlers explicitly annotated with
[CacheModule]
are cached.
Links
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.Extensions.Caching.Memory (>= 9.0.9)
- Space.Abstraction (>= 2.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last Updated |
---|---|---|
1.4.0 | 46 | 10/4/2025 |
1.3.1-preview | 227 | 9/19/2025 |
1.3.0-preview | 284 | 9/17/2025 |
1.2.0 | 128 | 9/13/2025 |
1.1.9-preview.13 | 26 | 9/12/2025 |
1.1.8 | 147 | 9/6/2025 |