Skip to content

rkdcoder/Cqrsly

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Cqrsly – Minimal CQRS Dispatcher for .NET (8+)

Cqrsly logo

NuGet Build & Publish License: MIT

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

Quickstart

1) Install

dotnet add package Cqrsly

2) Register

2.1) Standard approach (Register in Program.cs)

using Cqrsly;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCqrsly(cfg => cfg
    .AddHandlersFromAssemblyContaining<CreateAlertCommand>()
);

var app = builder.Build();

app.MapControllers();
app.Run();

2.2) Alternative approach (Assembly marker class)

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.

3) Create a Command

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;
    }
}

4) Handle the Command

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);
    }
}

5) Use in a Controller

[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);
    }
}

Query Example (for tests)

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));
    }
}

Features

  • Commands & Queries with strong typing (IRequest and IRequest<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)

License

MIT


Links

About

Cqrsly é um dispatcher CQRS minimalista para .NET 8+, inspirado no MediatR. Ele oferece uma configuração simples e de alta performance para commands, queries, notificações e pipeline behaviors, com registro fluente e pronto para produção em apenas 1–2 linhas no Program.cs.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages