SoulNETLib.Clean.Application 0.4.3

There is a newer version of this package available.
See the version list below for details.
dotnet add package SoulNETLib.Clean.Application --version 0.4.3
                    
NuGet\Install-Package SoulNETLib.Clean.Application -Version 0.4.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SoulNETLib.Clean.Application" Version="0.4.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SoulNETLib.Clean.Application" Version="0.4.3" />
                    
Directory.Packages.props
<PackageReference Include="SoulNETLib.Clean.Application" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SoulNETLib.Clean.Application --version 0.4.3
                    
#r "nuget: SoulNETLib.Clean.Application, 0.4.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SoulNETLib.Clean.Application@0.4.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SoulNETLib.Clean.Application&version=0.4.3
                    
Install as a Cake Addin
#tool nuget:?package=SoulNETLib.Clean.Application&version=0.4.3
                    
Install as a Cake Tool

SoulNETLib.Clean.Application

Application layer building blocks for Clean Architecture with CQRS. Provides command/query handler interfaces, a pipeline behavior system for cross-cutting concerns, built-in validation behavior, and DI registration extensions.

Installation

dotnet add package SoulNETLib.Clean.Application

Requirements: .NET 10+. Depends on SoulNETLib.Clean.Domain and Microsoft.Extensions.DependencyInjection.Abstractions.

Features

  • CQRS interfacesICommand, ICommand<T>, IQuery<T>, ICommandHandler<>, IQueryHandler<>
  • Pipeline behaviors — Middleware-style interceptors for commands and queries
  • Validation behavior — Runs all registered validators before handler execution, aggregates errors
  • DI extensions — Type-safe registration of handlers, validators, and pipeline wiring

Quick Start

Define a command and handler

using SoulNETLib.Clean.Application.Abstractions.CQRS;
using SoulNETLib.Clean.Domain;

public static class CreateProject
{
    public sealed record Command(string Name, string Description) : ICommand<Guid>;

    public sealed class Handler : ICommandHandler<Command, Guid>
    {
        public async Task<Result<Guid>> Handle(Command command, CancellationToken ct)
        {
            var id = Guid.NewGuid();
            // ... persist project
            return Result.Success(id);
        }
    }
}

Define a query and handler

public static class GetProjects
{
    public sealed record Query(string? Filter) : IQuery<IReadOnlyList<ProjectModel>>;

    public sealed class Handler : IQueryHandler<Query, IReadOnlyList<ProjectModel>>
    {
        public async Task<Result<IReadOnlyList<ProjectModel>>> Handle(Query query, CancellationToken ct)
        {
            // ... fetch from database
            return Result.Success<IReadOnlyList<ProjectModel>>(projects);
        }
    }
}

Register handlers with pipeline support

using SoulNETLib.Clean.Application.DependencyInjection;

services.AddCommandHandler<CreateProject.Command, Guid, CreateProject.Handler>();
services.AddQueryHandler<GetProjects.Query, IReadOnlyList<ProjectModel>, GetProjects.Handler>();

Add validation

Implement ICommandValidator<TCommand> for your commands:

using SoulNETLib.Clean.Application.Abstractions.Validation;
using SoulNETLib.Clean.Domain;

public sealed class CreateProjectValidator : ICommandValidator<CreateProject.Command>
{
    public Task<Error[]> ValidateAsync(CreateProject.Command command, CancellationToken ct)
    {
        var errors = new List<Error>();

        if (string.IsNullOrWhiteSpace(command.Name))
            errors.Add(Error.Validation("name", "Name is required"));

        return Task.FromResult(errors.ToArray());
    }
}

Register the validator and enable the validation behavior:

using SoulNETLib.Clean.Application.Behaviors;
using SoulNETLib.Clean.Application.DependencyInjection;

// Register validation behavior globally (once)
services.AddScoped(typeof(IPipelineBehavior<>), typeof(ValidationBehavior<>));
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));

// Register validators per command
services.AddCommandValidator<CreateProject.Command, CreateProjectValidator>();

All validators for a command run concurrently. Errors are aggregated into a single ValidationResult — the handler is never called if validation fails.

Custom pipeline behaviors

Create cross-cutting behaviors (logging, timing, authorization):

using SoulNETLib.Clean.Application.Abstractions.CQRS;
using SoulNETLib.Clean.Domain;

public sealed class LoggingBehavior<TCommand, TResponse> : IPipelineBehavior<TCommand, TResponse>
    where TCommand : ICommand<TResponse>
{
    public async Task<Result<TResponse>> Handle(
        TCommand command,
        PipelineStep<TResponse> next,
        CancellationToken cancellationToken)
    {
        Console.WriteLine($"Handling {typeof(TCommand).Name}");
        var result = await next();
        Console.WriteLine($"Handled {typeof(TCommand).Name}: {(result.IsSuccess ? "Success" : "Failure")}");
        return result;
    }
}

Architecture

┌─────────────────────────────────────────┐
│  Presentation (Web API / Blazor)        │
│  Injects ICommandHandler / IQueryHandler│
└──────────────────┬──────────────────────┘
                   │
┌──────────────────▼──────────────────────┐
│  Pipeline Behaviors (registered order)  │
│  ValidationBehavior → LoggingBehavior   │
└──────────────────┬──────────────────────┘
                   │
┌──────────────────▼──────────────────────┐
│  Command/Query Handler                  │
│  Business logic execution               │
└─────────────────────────────────────────┘

Behaviors execute in registration order (first registered = outermost). If no behaviors are registered, handlers are invoked directly with no overhead.

Feedback

Found a bug or have a suggestion? Open an issue on GitHub.

Contributing

Contributions are welcome! Fork the repository, make your changes, and submit a pull request. Please ensure all existing tests pass.

License

This package is licensed under the MIT License.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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.4.6 232 5/23/2026
0.4.5 115 5/18/2026
0.4.4 105 5/17/2026
0.4.3 176 5/11/2026
0.4.2 119 5/7/2026
0.4.1 105 5/6/2026
0.4.0 94 5/6/2026
0.3.0 213 3/13/2026
0.2.3 344 6/27/2025