Kodster.CQRS
0.1.0
dotnet add package Kodster.CQRS --version 0.1.0
NuGet\Install-Package Kodster.CQRS -Version 0.1.0
<PackageReference Include="Kodster.CQRS" Version="0.1.0" />
<PackageVersion Include="Kodster.CQRS" Version="0.1.0" />
<PackageReference Include="Kodster.CQRS" />
paket add Kodster.CQRS --version 0.1.0
#r "nuget: Kodster.CQRS, 0.1.0"
#:package Kodster.CQRS@0.1.0
#addin nuget:?package=Kodster.CQRS&version=0.1.0
#tool nuget:?package=Kodster.CQRS&version=0.1.0
Kodster.CQRS
A request/handler abstraction with no mediator in the middle.
Handlers are injected and called directly — IRequestHandler<TRequest, TResponse> is an
ordinary service. There is no ISender, no runtime type lookup, and a missing handler is a
compile error rather than a surprise at startup.
dotnet add package Kodster.CQRS
Brings in Kodster.Results and FluentValidation. Targets .NET 10.
You also need FluentValidation's DI package in whichever project registers validators:
dotnet add package FluentValidation.DependencyInjectionExtensions
Defining a request
A request is a marker. Use IRequest<TResponse> when there is something to return and
IRequest when there is not.
public sealed record GetUserQuery(Guid UserId) : IRequest<UserResponse>;
internal sealed class GetUserQueryHandler(IUserRepository users)
: IRequestHandler<GetUserQuery, UserResponse>
{
public async Task<Result<UserResponse>> Handle(
GetUserQuery request,
CancellationToken cancellationToken)
{
var user = await users.FindAsync(request.UserId, cancellationToken);
return user is null
? Error.NotFound("User.NotFound", "User was not found.")
: new UserResponse(user.Id, user.Nickname);
}
}
Handlers return Result or Result<T>, so expected failures are return values. See
Kodster.Results for the error model.
Validation
Write a normal FluentValidation validator. It runs before the handler, and a failure
short-circuits with every rule violation collected into a ValidationResult.
public sealed class GetUserQueryValidator : AbstractValidator<GetUserQuery>
{
public GetUserQueryValidator()
{
RuleFor(query => query.UserId).NotEmpty();
}
}
Validators must be public. AddValidatorsFromAssembly skips internal types unless you
pass includeInternalTypes: true. An internal validator is not an error — it is simply never
registered, so validation silently does not run for that request.
Requests with no validator registered skip validation entirely.
Registration
var assembly = typeof(GetUserQuery).Assembly;
services.AddValidatorsFromAssembly(assembly);
services.AddRequestHandlersFromAssembly(assembly);
AddRequestHandlersFromAssembly scans the assembly for every IRequestHandler<> and
IRequestHandler<,> implementation and registers each as transient, wrapped in a fixed
pipeline:
LoggingHandlerDecorator → ValidationHandlerDecorator → your handler
Logging sits outermost, so it records validation failures as well as handler ones. Each request is logged with a correlation guid at start and end, along with elapsed milliseconds, and failures log their error code and description.
The pipeline is fixed; there is no registration hook for adding your own decorators.
Calling a handler
Inject the handler interface wherever you need it — including directly into a minimal API endpoint, with no dispatcher in between.
app.MapGet("users/{id:guid}", async (
Guid id,
IRequestHandler<GetUserQuery, UserResponse> handler,
CancellationToken cancellationToken) =>
{
var result = await handler.Handle(new GetUserQuery(id), cancellationToken);
return result.IsSuccess
? Results.Ok(result.Value)
: result.ToProblemDetails();
});
ToProblemDetails() comes from
Kodster.Results.AspNetCore.
Companion packages
- Kodster.Results — the
ResultandErrortypes handlers return. No dependencies. - Kodster.Results.AspNetCore —
maps a failed
Resultonto an HTTPProblemDetailsresponse.
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- FluentValidation (>= 12.1.1)
- Kodster.Results (>= 0.1.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 10.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 |
|---|---|---|
| 0.1.0 | 110 | 8/19/2026 |