Cap.MiniCqrs.Caching.Memory
0.1.0
dotnet add package Cap.MiniCqrs.Caching.Memory --version 0.1.0
NuGet\Install-Package Cap.MiniCqrs.Caching.Memory -Version 0.1.0
<PackageReference Include="Cap.MiniCqrs.Caching.Memory" Version="0.1.0" />
<PackageVersion Include="Cap.MiniCqrs.Caching.Memory" Version="0.1.0" />
<PackageReference Include="Cap.MiniCqrs.Caching.Memory" />
paket add Cap.MiniCqrs.Caching.Memory --version 0.1.0
#r "nuget: Cap.MiniCqrs.Caching.Memory, 0.1.0"
#:package Cap.MiniCqrs.Caching.Memory@0.1.0
#addin nuget:?package=Cap.MiniCqrs.Caching.Memory&version=0.1.0
#tool nuget:?package=Cap.MiniCqrs.Caching.Memory&version=0.1.0
Capybaras MiniCqrs
A minimal, fast-path CQRS dispatcher for .NET. MiniCqrs focuses on zero-reflection handler execution, DI-first design, and opt-in extras (pipeline behaviors, caching, source-generated extensions). This repository contains the core libraries that can be published to NuGet (e.g., Cap.MiniCqrs, Cap.MiniCqrs.Caching.Memory).
Goals
- Zero-reflection dispatch path for commands and queries.
- Tiny API surface (no magic base classes or runtime type tables).
- Friendly to AOT/trimming scenarios.
- Optional ergonomic add-ons that do not compromise performance (caching/idempotency decorators, pipeline behaviors, source-generated extensions).
- OSS-ready: docs, samples, tests, CI, SemVer, MIT license.
Fast-Path Dispatcher
namespace Cap.MiniCqrs;
public interface IDispatcher
{
Task<TResponse> Send<TResponse, TCommand>(TCommand command, CancellationToken ct = default)
where TResponse : notnull
where TCommand : ICommand<TResponse>;
Task<TResponse> Query<TResponse, TQuery>(TQuery query, CancellationToken ct = default)
where TResponse : notnull
where TQuery : IQuery<TResponse>;
}
using Cap.MiniCqrs;
using Cap.MiniCqrs.Dispatching;
services.AddScoped<IDispatcher, Dispatcher>();
services.AddScoped<ICommandHandler<CreateUserCommand, CreateUserResult>, CreateUserHandler>();
var result = await dispatcher.Send<CreateUserResult, CreateUserCommand>(new CreateUserCommand(request), ct);
Handlers are resolved via DI as closed generics and invoked directly—no reflection or dynamic invocation occurs during dispatch.
Architecture
flowchart TD
Caller --> Dispatcher[IDispatcher]
Dispatcher -->|optional| Pipeline[Pipeline Behaviors]
Pipeline --> Core[Fast Path Dispatcher]
Core --> Handler
Handler --> Response
Pipeline -. optional .-> Cache[IRequestResultCache]
Components
Cap.MiniCqrs:ICommand<T>,IQuery<T>, handler interfaces,IDispatcher.Cap.MiniCqrs.Dispatching:Dispatcherfast-path implementation.Cap.MiniCqrs.Caching:ICacheKeyProvider,IRequestResultCache,CachedDispatcher.Cap.MiniCqrs.Caching.Memory: optional HybridCache-backed result cache implementation.- Planned namespaces:
Cap.MiniCqrs.Pipeline,Cap.MiniCqrs.SourceGen.
Optional Enhancements
- Pipeline Behaviors – wrap handler execution for logging, validation, timing, or idempotency.
- Caching / Idempotency – requests implementing
ICacheKeyProvidercan be cached or deduplicated viaIRequestResultCacheusing either the fast-pathStrictCachedDispatcher(compile-time constraint) or the decoratorCachedDispatcher(wraps anyIDispatcher). - Source-Generated Extensions – Roslyn generator emits strongly-typed
dispatcher.Send(command)extensions (no runtime reflection, best ergonomics).
Caching Usage
using Cap.MiniCqrs;
using Cap.MiniCqrs.Caching;
using Cap.MiniCqrs.Caching.Memory;
using Cap.MiniCqrs.Dispatching;
// Request provides a cache key (e.g., idempotency token)
public sealed record FinishGameCommand(long UserId, long MessageId)
: ICommand<FinishGameResponse>, ICacheKeyProvider
{
public string CacheKey => $"finish:{UserId}:{MessageId}";
}
// DI
services.AddHybridCache();
services.AddSingleton<IRequestResultCache, MemoryRequestResultCache>();
services.AddScoped<Dispatcher>();
services.AddScoped<IDispatcher>(sp =>
{
var inner = sp.GetRequiredService<Dispatcher>();
var cache = sp.GetRequiredService<IRequestResultCache>();
return new CachedDispatcher(inner, cache);
});
// Usage
var response = await dispatcher.Send<FinishGameResponse, FinishGameCommand>(
new FinishGameCommand(userId, messageId),
cancellationToken);
// Strict dispatcher skips runtime checks by requiring cacheable requests at compile time
ICachedDispatcher strict = new StrictCachedDispatcher(dispatcher, cache);
var response2 = await strict.Send<FinishGameResponse, FinishGameCommand>(
new FinishGameCommand(userId, messageId),
cancellationToken);
Need to revoke cache entries? Call IRequestResultCache.InvalidateAsync(key) for a single idempotency key or InvalidateByTagsAsync(tags) to purge groups (e.g., all cache for a user).
Need custom lifetimes? Call
IRequestResultCache.GetOrAddAsyncwith aTimeSpan ttland optional cachetagsto override defaults per request.
Roadmap
- v0.1.0 – core dispatcher, DI extensions, README, tests, sample.
- v0.2.x – pipeline behaviors + memory caching package.
- v0.3.x – source generator (extensions or invoker tables).
- v1.0.0 – documentation polish, AOT guidance, benchmarks, community governance.
Repository Layout
Cap.MiniCqrs.sln
src/
Cap.MiniCqrs/
ICommand.cs
IQuery.cs
ICommandHandler.cs
IQueryHandler.cs
IDispatcher.cs
Dispatching/Dispatcher.cs
Caching/
ICacheKeyProvider.cs
IRequestResultCache.cs
CachedDispatcher.cs
ICachedDispatcher.cs
StrictCachedDispatcher.cs
Cap.MiniCqrs.Caching.Memory/
MemoryRequestResultCache.cs
samples/
DispatcherSample/
tests/
Cap.MiniCqrs.Tests/
Samples
samples/DispatcherSample– minimal console app showing how to wire the dispatcher viaAddMiniCqrs()/AddMiniCqrsHandlersFrom(...)and send/query handlers. Run withdotnet run --project samples/DispatcherSample.samples/SliceSlotWebApi– trimmed-down “slot” Web API that uses vertical-slice folders (Features/*) plus theGameStateStorein-memory aggregate. It exposes/api/game/init,/api/game/spin, and/api/game/collect. Run viadotnet run --project samples/SliceSlotWebApiand exercise the endpoints with the bundledSliceSlotWebApi.httpfile (REST Client / HTTP REPL friendly).
Tests
tests/Cap.MiniCqrs.Tests– xUnit coverage for send/query dispatching and the DI extensions. Execute viadotnet test.
License
MIT (to be added before publishing the NuGet packages).
Made with 🍃 by Capybaras.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. 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. |
-
net9.0
- Cap.MiniCqrs (>= 0.1.0)
- Microsoft.Extensions.Caching.Hybrid (>= 9.3.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 |
|---|---|---|
| 0.1.0 | 471 | 11/19/2025 |