Cqrsly is a plug-and-play CQRS dispatcher for .NET 8+ with a MediatR-like API. It provides a minimal, high-performance setup for:
- Commands & Queries with return types
- Pipeline behaviors (logging, validation, etc.)
- Notifications (domain events) with sequential dispatch
- Fluent API registration for easy integration
- Minimal, production-ready setup: 1–2 lines in
Program.cs
dotnet add package Cqrslyusing Cqrsly;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCqrsly(cfg => cfg
.AddHandlersFromAssemblyContaining<CreateAlertCommand>()
);
var app = builder.Build();
app.MapControllers();
app.Run();Creating an empty class to use as a marker:
internal sealed class ApplicationAssemblyMarker { }Applying the marker class to scan all commands/queries:
builder.Services.AddCqrsly(cfg => cfg
.AddHandlersFromAssemblyContaining<ApplicationAssemblyMarker>()
);- Advantage: decouples dependency injection from specific commands/queries.
- Recommended in DDD/Hexagonal architectures where DI bootstrap should remain independent from feature-level details.
- Useful in larger solutions where there isn’t an obvious “root” command.
Multiple marker classes:
builder.Services.AddCqrsly(cfg => cfg
.AddHandlersFromAssemblyContaining<ApplicationAssemblyMarker>()
.AddHandlersFromAssemblyContaining<AnotherAssemblyMarker>()
);- Advantage: register handlers from multiple assemblies in one application.
- Useful for modular architectures or when sharing bounded contexts.
using Cqrsly;
using Teste.Dto;
public sealed class CreateAlertCommand : IRequest<CommandResultDto<object?>>
{
public string Title { get; }
public string Content { get; }
public CreateAlertCommand(string title, string content)
{
Title = title;
Content = content;
}
}using Cqrsly;
using Teste.Command;
using Teste.Dto;
public sealed class CreateAlertCommandHandler : IRequestHandler<CreateAlertCommand, CommandResultDto<object?>>
{
private readonly IAlertCommandRepository _repository;
public CreateAlertCommandHandler(IAlertCommandRepository repository)
=> _repository = repository;
public async Task<CommandResultDto<object?>> Handle(CreateAlertCommand request, CancellationToken ct)
{
var id = await _repository.CreateAlertAsync(request.Title, request.Content, ct);
var payload = new { Id = id, request.Title };
return CommandResultDto<object?>.SuccessResult("Alert created.", payload);
}
}[ApiController]
[Route("api/alerts")]
public class AlertsController : ControllerBase
{
private readonly ICqrsly _cqrsly;
public AlertsController(ICqrsly cqrsly) => _cqrsly = cqrsly;
[HttpPost]
public async Task<IActionResult> Create([FromBody] CreateAlertDto dto, CancellationToken ct)
{
var cmd = new CreateAlertCommand(dto.Title, dto.Content);
// Two options:
// 1) MediatR-style (type inference)
var result = await _cqrsly.Send(cmd, ct);
// 2) Explicit style (TRequest, TResponse)
// var result = await _cqrsly.Send<CreateAlertCommand, CommandResultDto<object?>>(cmd, ct);
return Ok(result);
}
}using Cqrsly;
using Teste.Dto;
public sealed class GetAlertsQuery : IRequest<CommandResultDto<IReadOnlyList<AlertDto>>>
{
public string? TitleContains { get; }
public GetAlertsQuery(string? titleContains) => TitleContains = titleContains;
}
public sealed class GetAlertsQueryHandler : IRequestHandler<GetAlertsQuery, CommandResultDto<IReadOnlyList<AlertDto>>>
{
public Task<CommandResultDto<IReadOnlyList<AlertDto>>> Handle(GetAlertsQuery request, CancellationToken ct)
{
var list = new List<AlertDto> {
new AlertDto { Id = 1, Title = "Test", Content = "Mocked" }
};
return Task.FromResult(CommandResultDto<IReadOnlyList<AlertDto>>.SuccessResult("Query executed.", list));
}
}- Commands & Queries with strong typing (
IRequestandIRequest<T>) - Pipeline behaviors (
IPipelineBehavior<TReq,TRes>) for logging, validation, telemetry - Notifications (
INotification) with sequential dispatch - Fluent API registration (
AddCqrsly(cfg => ...)) - Lightweight & high-performance (delegate-based pipeline, no extra deps)
- MediatR-like ergonomics (Send, Publish, IRequest, INotification)
MIT
- Repository: https://github.com/rkdcoder/Cqrsly
- NuGet: https://www.nuget.org/packages/Cqrsly