Skip to content

A lightweight, dependency-free CQRS library for .NET 8/9/10. Supports commands (with and without return values), queries, a minimal reflection-safe dispatcher, and includes full console & Minimal API samples.

License

Notifications You must be signed in to change notification settings

livedcode/MinimalCQRS

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

2 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

MinimalCQRS

A lightweight, dependency-free CQRS library for .NET (net8 / net9 / net10), designed for developers who want:

  • Simple Commands and Queries
  • Optional Command return values
  • Reflection-safe, minimal Dispatcher
  • Clean Vertical Slice architecture
  • Ready-to-use Console + Minimal API samples
  • Full unit test coverage
  • Zero dependencies (no MediatR, no pipelines)

Author: livedcode
License: MIT


πŸ“¦ Features

βœ” Commands (with & without return values)

public sealed class CreateLogCommand : ICommand { }
public sealed class CreateUserCommand : ICommand<int> { }

βœ” Queries with typed results

public sealed class GetUserQuery : IQuery<UserDto> { }

βœ” Dispatcher

  • SendAsync(ICommand)
  • SendAsync<TResult>(ICommand<TResult>)
  • QueryAsync<TResult>(IQuery<TResult>)

βœ” Samples included

  • Minimal API (Vertical Slice)
  • Console application

βœ” Fully unit tested

Uses xUnit


🧱 Project Structure

MinimalCQRS/
β”‚
β”œβ”€β”€ README.md
β”œβ”€β”€ LICENSE
β”œβ”€β”€ CHANGELOG.md
β”‚
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ MinimalCQRS/
β”‚   β”‚   β”œβ”€β”€ Commands/
β”‚   β”‚   β”‚   β”œβ”€β”€ ICommand.cs
β”‚   β”‚   β”‚   β”œβ”€β”€ ICommandHandler.cs
β”‚   β”‚   β”‚
β”‚   β”‚   β”œβ”€β”€ Queries/
β”‚   β”‚   β”‚   β”œβ”€β”€ IQuery.cs
β”‚   β”‚   β”‚   β”œβ”€β”€ IQueryHandler.cs
β”‚   β”‚   β”‚
β”‚   β”‚   β”œβ”€β”€ Execution/
β”‚   β”‚   β”‚   β”œβ”€β”€ IDispatcher.cs
β”‚   β”‚   β”‚   └── Dispatcher.cs
β”‚   β”‚   β”‚
β”‚   β”‚   └── MinimalCQRS.csproj
β”‚   β”‚
β”‚   β”œβ”€β”€ MinimalCQRS.SampleConsole/
β”‚   β”‚   β”œβ”€β”€ Program.cs
β”‚   β”‚   β”‚
β”‚   β”‚   β”œβ”€β”€ Commands/
β”‚   β”‚   β”‚   β”œβ”€β”€ NoReturn/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ CreateLogCommand.cs
β”‚   β”‚   β”‚   β”‚   └── CreateLogHandler.cs
β”‚   β”‚   β”‚   β”‚
β”‚   β”‚   β”‚   └── WithReturn/
β”‚   β”‚   β”‚       β”œβ”€β”€ CreateUserCommand.cs
β”‚   β”‚   β”‚       └── CreateUserHandler.cs
β”‚   β”‚   β”‚
β”‚   β”‚   β”œβ”€β”€ Models/UserDto.cs
β”‚   β”‚   β”œβ”€β”€ Queries/
β”‚   β”‚   β”‚   β”œβ”€β”€ GetUserQuery.cs
β”‚   β”‚   β”‚   └── GetUserHandler.cs
β”‚   β”‚   β”‚
β”‚   β”‚   └── MinimalCQRS.SampleConsole.csproj
β”‚   β”‚
β”‚   └── MinimalCQRS.Sample.Api/
β”‚       β”œβ”€β”€ Program.cs
β”‚       β”‚
β”‚       β”œβ”€β”€ Features/
β”‚       β”‚   β”œβ”€β”€ Logs/
β”‚       β”‚   β”‚   └── Create/
β”‚       β”‚   β”‚       β”œβ”€β”€ CreateLogCommand.cs
β”‚       β”‚   β”‚       β”œβ”€β”€ CreateLogHandler.cs
β”‚       β”‚   β”‚       └── Endpoint.cs
β”‚       β”‚   β”‚
β”‚       β”‚   └── Users/
β”‚       β”‚       β”œβ”€β”€ Create/
β”‚       β”‚       β”‚   β”œβ”€β”€ CreateUserCommand.cs
β”‚       β”‚       β”‚   β”œβ”€β”€ CreateUserHandler.cs
β”‚       β”‚       β”‚   └── Endpoint.cs
β”‚       β”‚       β”‚
β”‚       β”‚       └── Get/
β”‚       β”‚           β”œβ”€β”€ GetUserQuery.cs
β”‚       β”‚           β”œβ”€β”€ GetUserHandler.cs
β”‚       β”‚           β”œβ”€β”€ UserDto.cs
β”‚       β”‚           └── Endpoint.cs
β”‚       β”‚
β”‚       └── MinimalCQRS.Sample.Api.csproj
β”‚
└── tests/
    └── MinimalCQRS.Tests/
        β”œβ”€β”€ DispatcherTests.cs
        └── MinimalCQRS.Tests.csproj

πŸš€ How to Use the Library

1️⃣ Register Dispatcher & Handlers (DI)

services.AddScoped<IDispatcher, Dispatcher>();

// Command (no return)
services.AddScoped<ICommandHandler<CreateLogCommand>, CreateLogHandler>();

// Command (with return)
services.AddScoped<ICommandHandler<CreateUserCommand, int>, CreateUserHandler>();

// Query
services.AddScoped<IQueryHandler<GetUserQuery, UserDto>, GetUserHandler>();

2️⃣ Using Commands

πŸ”Ή Command WITHOUT return

Define command:

public sealed class CreateLogCommand : ICommand
{
    public string Message { get; init; } = string.Empty;
}

Handler:

public sealed class CreateLogHandler : ICommandHandler<CreateLogCommand>
{
    public Task HandleAsync(CreateLogCommand cmd, CancellationToken ct = default)
    {
        Console.WriteLine($"LOG: {cmd.Message}");
        return Task.CompletedTask;
    }
}

Execute:

await dispatcher.SendAsync(new CreateLogCommand { Message = "Hello!" });

πŸ”Ή Command WITH return (e.g., UserId)

Command

public sealed class CreateUserCommand : ICommand<int>
{
    public string Email { get; init; } = string.Empty;
}

Handler

public sealed class CreateUserHandler : ICommandHandler<CreateUserCommand, int>
{
    private static int _nextId = 1;

    public Task<int> HandleAsync(CreateUserCommand cmd, CancellationToken ct = default)
    {
        return Task.FromResult(_nextId++);
    }
}

Execute

int id = await dispatcher.SendAsync(new CreateUserCommand { Email = "demo@test.com" });

3️⃣ Using Queries

Query

public sealed class GetUserQuery : IQuery<UserDto>
{
    public int UserId { get; init; }
}

Handler

public sealed class GetUserHandler : IQueryHandler<GetUserQuery, UserDto>
{
    public Task<UserDto> HandleAsync(GetUserQuery query, CancellationToken ct = default)
    {
        return Task.FromResult(new UserDto { UserId = query.UserId });
    }
}

Execute

var user = await dispatcher.QueryAsync(new GetUserQuery { UserId = 10 });

πŸ§ͺ Unit Tests Included

  • Tests for void command
  • Tests for return command
  • Tests for query
  • Tests for dispatcher behavior

Example:

[Fact]
public async Task SendAsync_CommandWithReturn_Should_Return_Id()
{
    var id = await dispatcher.SendAsync(new CreateUserCommand { Email = "abc@test.com" });
    Assert.True(id > 0);
}

πŸ“œ License

MIT License β€” see LICENSE file.


⭐ Summary

MinimalCQRS is:

  • βœ” Simple
  • βœ” Fast
  • βœ” Production-ready
  • βœ” No 3rd party dependencies
  • βœ” Perfect for Vertical Slice or Clean Architecture
  • βœ” Includes samples + tests

A great lightweight alternative to MediatR when you only need pure CQRS, nothing else.

About

A lightweight, dependency-free CQRS library for .NET 8/9/10. Supports commands (with and without return values), queries, a minimal reflection-safe dispatcher, and includes full console & Minimal API samples.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages