NPv.CQS.Abstractions
3.0.0
dotnet add package NPv.CQS.Abstractions --version 3.0.0
NuGet\Install-Package NPv.CQS.Abstractions -Version 3.0.0
<PackageReference Include="NPv.CQS.Abstractions" Version="3.0.0" />
<PackageVersion Include="NPv.CQS.Abstractions" Version="3.0.0" />
<PackageReference Include="NPv.CQS.Abstractions" />
paket add NPv.CQS.Abstractions --version 3.0.0
#r "nuget: NPv.CQS.Abstractions, 3.0.0"
#:package NPv.CQS.Abstractions@3.0.0
#addin nuget:?package=NPv.CQS.Abstractions&version=3.0.0
#tool nuget:?package=NPv.CQS.Abstractions&version=3.0.0
NPv.CQS.Abstractions
Minimal, dependency-free contracts for applications following the Command-Query Separation (CQS) pattern.
π Breaking changes
v3.0.0
- Target framework updated to
net10.0(droppednet9.0support).
This is a personal library that focuses on the latest .NET runtime to keep maintenance simple and enjoyable.
β¨ Overview
NPv.CQS.Abstractions is a foundational library containing interfaces and contracts for building systems based on the CommandβQuery Separation (CQS) principle.
It does not include any infrastructure or implementation β only the minimal building blocks that let infrastructure resolve and invoke handlers automatically.
Use this package in your domain, application, or core layers to define behaviors without pulling in any dependencies.
π§ Interfaces Included
π’ Commands
| Interface | Purpose |
|---|---|
ICommand<TContext> |
Represents an action that changes system state and returns a Result |
ICommand<TContext, TResult> |
Command that changes system state and returns a Result<TResult> |
ICommandContext |
Marker type for command input/context |
ICommandContext<TResult> |
Marker type for command input that implies a typed result |
ICommandBuilder |
Resolves and executes a command for a given context (container-agnostic contract) |
ICommandExecutor |
Higher-level orchestrator for executing commands (e.g., can be wrapped with Unit of Work in infrastructure), returns a Result |
CommandExecutorExtensions |
Convenience extension methods to execute commands with or without results in a concise way |
π΅ Queries
| Interface | Purpose |
|---|---|
IQuery<TCriterion, TResult> |
Read-only operation returning data for a specific criterion |
ICriterion |
Input object used to filter or parameterize queries |
IQueryBuilder |
Fluent entrypoint: ForAsync<TResult>() ... With<TCriterion>(criterion) |
IQueryFor<TResult> |
Continuation interface returned by IQueryBuilder for a specific TResult |
π¨ Breaking Changes in v2.0.0+
- All commands now return a
ResultorResult<TResult>instead of beingvoidtasks. ICommandContextsplit into two flavors:ICommandContext(no result) andICommandContext<TResult>(with typed result).- Extension methods added for shorter syntax when executing commands.
Before (v1.x)
public class CreateOrderCommand : ICommand<CreateOrderCommandContext>
{
public Task ExecuteAsync(CreateOrderCommandContext context)
{
// Domain logic
return Task.CompletedTask;
}
}
After (v2.x)
public class CreateOrderCommand : ICommand<CreateOrderCommandContext>
{
public Task<Result> ExecuteAsync(CreateOrderCommandContext context)
{
if (context.Amount <= 0)
return Task.FromResult(Result.Failure(new Error("Validation.Invalid", "Amount")));
return Task.FromResult(Result.Success());
}
}
Commands with results:
public record LoginUserCommandContext(string Email, string Password) : ICommandContext<LoginUserCommandResult>;
public record LoginUserCommandResult(string Email, string Token);
public class LoginUserCommand : ICommand<LoginUserCommandContext, LoginUserCommandResult>
{
public Task<Result<LoginUserCommandResult>> ExecuteAsync(LoginUserCommandContext context, CancellationToken ct = default)
{
if (context.Password != "123")
return Task.FromResult(Result<LoginUserCommandResult>.Failure(new Error("Auth.Invalid", "Bad password")));
return Task.FromResult(new LoginUserCommandResult(context.Email, "jwt-token"));
}
}
π¦ Installation
dotnet add package NPv.CQS.Abstractions
π‘ Examples
Define a command without result
public record BanUserCommandContext(Guid UserId) : ICommandContext;
public class BanUserCommand : ICommand<BanUserCommandContext>
{
public Task<Result> ExecuteAsync(BanUserCommandContext context, CancellationToken ct = default)
{
// Domain logic (ban user)
return Task.FromResult(Result.Success());
}
}
Define a command with result
public record CreateUserContext(string Email, string Password) : ICommandContext<UserDto>;
public record UserDto(Guid Id, string Email);
public class CreateUserCommand : ICommand<CreateUserContext, UserDto>
{
public Task<Result<UserDto>> ExecuteAsync(CreateUserContext context, CancellationToken ct = default)
{
if (string.IsNullOrWhiteSpace(context.Email))
return Task.FromResult(Result<UserDto>.Failure(new Error("Validation.Invalid", "Email required")));
return Task.FromResult(new UserDto(Guid.NewGuid(), context.Email));
}
}
Define a query
public record FindById(Guid Id) : ICriterion;
public class FindOrderByIdQuery(IOrderService orders) : IQuery<FindById, Order>
{
public Task<Order> AskAsync(FindById criterion) =>
orders.GetAsync(criterion.Id);
}
Use in application code
public class OrdersController(ICommandExecutor exec, IQueryBuilder queries)
{
public async Task<IActionResult> Create(Guid id, decimal amount)
{
var result = await exec.ExecuteAsync(new CreateOrderCommandContext(id, amount));
return result.IsSuccess ? Ok() : BadRequest(result.Errors);
}
public async Task<IActionResult> Login(string email, string password)
{
var result = await exec.ExecuteAsync<LoginUserCommandResult>(
new LoginUserCommandContext(email, password));
return result.IsSuccess ? Ok(result.Value) : Unauthorized(result.Errors);
}
public Task<Order> Get(Guid id) =>
queries.ForAsync<Order>().With(new FindById(id));
}
Note:
ICommandExecutoris just a contract; infrastructure can provide an implementation that wraps execution in a Unit of Work (seeNPv.Uow.Abstractions) or adds logging/telemetry/retries.
π Designed For Use With
NPv.CQS.Infrastructureβ runtime execution (dispatch via DI, Autofac/MS.DI modules)NPv.Uow.Abstractionsβ optional Unit of Work contract for transactional execution- Any DI container or runtime
βοΈ License
MIT β you are free to use this in commercial and open-source software.
| 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
- NPv.ResultPattern (>= 2.0.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on NPv.CQS.Abstractions:
| Package | Downloads |
|---|---|
|
NPv.CQS.Infrastructure
Provides command and query execution infrastructure for CQS-based applications, with builder implementations. |
GitHub repositories
This package is not used by any popular GitHub repositories.