skills/dotnet/patterns/pipeline-decorator/SKILL.md
Build cross-cutting concern pipelines using decorator pattern for handlers in Clean Architecture applications. Use when: - Implementing cross-cutting concerns (logging, validation, transaction, etc.) - Building handler pipelines with multiple concerns - Composing decorators for different operation types - Separating cross-cutting logic from business logic - Applying concerns in specific order Triggers: "decorator", "pipeline", "cross-cutting", "handler decorator", "middleware", "aspect"
npx skillsauth add yeeehaooo/WorkSpace pipeline-decoratorInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Build cross-cutting concern pipelines using decorator pattern for handlers.
Applies to:
// Application Layer
public interface ICommandHandler<TCommand>
{
Task<Result> HandleAsync(TCommand command, CancellationToken ct = default);
}
public abstract class CommandHandlerDecorator<TCommand> : ICommandHandler<TCommand>
{
protected readonly ICommandHandler<TCommand> _next;
protected CommandHandlerDecorator(ICommandHandler<TCommand> next)
{
_next = next;
}
public abstract Task<Result> HandleAsync(TCommand command, CancellationToken ct = default);
}
// Infrastructure Layer
public class LoggingDecorator<TCommand> : CommandHandlerDecorator<TCommand>
{
private readonly ILogger<LoggingDecorator<TCommand>> _logger;
public LoggingDecorator(
ICommandHandler<TCommand> next,
ILogger<LoggingDecorator<TCommand>> logger) : base(next)
{
_logger = logger;
}
public override async Task<Result> HandleAsync(TCommand command, CancellationToken ct = default)
{
_logger.LogInformation("Handling command {CommandType}", typeof(TCommand).Name);
var stopwatch = Stopwatch.StartNew();
try
{
var result = await _next.HandleAsync(command, ct);
stopwatch.Stop();
_logger.LogInformation("Command handled in {ElapsedMs}ms", stopwatch.ElapsedMilliseconds);
return result;
}
catch (Exception ex)
{
stopwatch.Stop();
_logger.LogError(ex, "Command failed after {ElapsedMs}ms", stopwatch.ElapsedMilliseconds);
throw;
}
}
}
public class ValidationDecorator<TCommand> : CommandHandlerDecorator<TCommand>
{
private readonly IValidator<TCommand> _validator;
public ValidationDecorator(
ICommandHandler<TCommand> next,
IValidator<TCommand> validator) : base(next)
{
_validator = validator;
}
public override async Task<Result> HandleAsync(TCommand command, CancellationToken ct = default)
{
var validationResult = await _validator.ValidateAsync(command, ct);
if (!validationResult.IsValid)
{
return Result.Failure(string.Join(", ", validationResult.Errors.Select(e => e.ErrorMessage)));
}
return await _next.HandleAsync(command, ct);
}
}
// DI Registration
services.AddScoped<ICommandHandler<CreateOrderCommand>>(sp =>
{
var handler = new CreateOrderHandler(/* dependencies */);
var validated = new ValidationDecorator<CreateOrderCommand>(handler, /* validator */);
var logged = new LoggingDecorator<CreateOrderCommand>(validated, /* logger */);
return logged;
});
development
Create reusable .NET atomic capability code snippets that can be directly copied and pasted. Use when: - Creating single-purpose code snippets - Building reusable code templates - Implementing atomic technical capabilities - Creating copy-pasteable code blocks - Building snippet library for common patterns Triggers: "create snippet", "code snippet", "reusable snippet", "atomic snippet", "copy-paste code"
development
Create Docker Compose configuration for containerized .NET application development and deployment. Use when: - Containerizing .NET applications - Setting up local development environment with dependencies - Creating multi-container setups (API + DB + Redis) - Defining service dependencies and networking - Building docker-compose.yml for development or production Triggers: "docker compose", "containerize", "multi-container", "docker-compose.yml", "docker setup"
tools
Create adapter structure for integrating third-party APIs in Clean Architecture applications. Use when: - Integrating external APIs or services - Creating HTTP client adapters for third-party services - Implementing API integration with error handling - Setting up adapter pattern for external dependencies - Building resilient external service integrations Triggers: "api adapter", "third-party api", "external service", "http client adapter", "api integration"
development
Enterprise backend structure built on Clean Architecture, DDD, CQRS, and Vertical Slice API Design with Dapper-first persistence. Use when: - Creating new enterprise backend projects - Implementing Clean Architecture with DDD and CQRS - Building vertical slice API endpoints - Using Dapper as primary persistence mechanism - Organizing modules by UseCase-driven and Model-driven separation Triggers: "dmis structure", "clean architecture", "enterprise backend", "DDD CQRS", "vertical slice", "dapper"