Files
pi-config/extensions/rpiv-pi/skills/annotate-guidance/examples/subfolder-dotnet-application.md

2.4 KiB

Application Layer (CQRS + MediatR)

Responsibility

Command/query handlers orchestrating domain logic via MediatR pipeline. Sits between API controllers and Domain layer.

Dependencies

  • MediatR: Command/query dispatch
  • FluentValidation: Request validation via pipeline behavior
  • AutoMapper: Domain ↔ DTO mapping

Consumers

  • API Controllers: Send commands/queries via IMediator
  • Integration tests: Direct handler invocation

Module Structure

Application/
├── Common/
│   ├── Behaviors/          # MediatR pipeline (validation, logging)
│   └── Mappings/           # AutoMapper profiles
├── Features/               # One folder per aggregate
│   └── Orders/
│       ├── Commands/       # CreateOrder/, UpdateOrder/ (handler + validator + DTO)
│       └── Queries/        # GetOrder/, ListOrders/
└── DependencyInjection.cs  # Service registration

Handler Pattern (Command with Validation)

public record CreateOrderCommand(string CustomerId, List<LineItemDto> Items)
    : IRequest<Result<OrderDto>>;

public class CreateOrderValidator : AbstractValidator<CreateOrderCommand> {
    public CreateOrderValidator(IOrderRepository repo) {
        RuleFor(x => x.CustomerId).NotEmpty();
        RuleFor(x => x.Items).NotEmpty();
    }
}

public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, Result<OrderDto>> {
    public async Task<Result<OrderDto>> Handle(
        CreateOrderCommand request, CancellationToken ct) {
        var order = Order.Create(request.CustomerId, request.Items); // Domain factory
        await _repo.AddAsync(order, ct);
        await _unitOfWork.SaveChangesAsync(ct);
        return Result.Ok(_mapper.Map<OrderDto>(order));
    }
}

Architectural Boundaries

  • NO domain logic in handlers: Handlers orchestrate, domain objects contain logic
  • NO direct DbContext access: Use repository abstractions
  • NO cross-feature references: Features are independent vertical slices
## Adding a New Feature 1. Create folder under `Features/{Aggregate}/{Commands|Queries}/` 2. Add `Command`/`Query` record implementing `IRequest>` 3. Add `Validator` extending `AbstractValidator` 4. Add `Handler` implementing `IRequestHandler>` 5. Add AutoMapper profile in `Common/Mappings/` if new DTO