دکوراتور اعتبارسنجی با FluentValidation: ✅
internal sealed class ValidationCommandHandler<TCommand, TResponse>(...)
: ICommandHandler<TCommand, TResponse>
where TCommand : ICommand<TResponse>
{
public async Task<Result<TResponse>> Handle(TCommand command, CancellationToken cancellationToken)
{
// ... (منطق اعتبارسنجی قبل از اجرای handler اصلی) ...
}
}
⚠️ مهم: از آنجایی که ما با اینترفیسهای جنریک کار میکنیم، هر دکوراتور باید صراحتاً همان قرارداد جنریک را هدف قرار دهد.
در بخش بعدی، این را با استفاده از Scrutor به هم متصل خواهیم کرد.
راهاندازی DI ⚙️
با handlerها و دکوراتورهایمان، میتوانیم همه چیز را با استفاده از Scrutor ثبت کنیم.
services.Scan(scan => scan.FromAssembliesOf(typeof(DependencyInjection))
.AddClasses(classes => classes.AssignableTo(typeof(IQueryHandler<,>)), publicOnly: false)
.AsImplementedInterfaces()
.WithScopedLifetime()
// ... ثبت بقیه handlerها ...
);
🔹این کد اسمبلی اپلیکیشن را اسکن کرده و تمام command و query handlerها را ثبت میکند.
🔹سپس، دکوراتورها را برای اعتبارسنجی و لاگینگ اعمال میکنیم:
services.Decorate(typeof(ICommandHandler<,>), typeof(ValidationDecorator.CommandHandler<,>));
services.Decorate(typeof(ICommandHandler<,>), typeof(LoggingDecorator.CommandHandler<,>));
💡ترتیب مهم است. آخرین دکوراتور اعمال شده، بیرونیترین دکوراتور در زمان اجرا خواهد بود. بنابراین در این مثال، دکوراتور لاگینگ ابتدا اجرا میشود، سپس اعتبارسنجی و بعد handler اصلی.
استفاده از Minimal API 🎯
هنگامی که همه چیز متصل شد، استفاده از یک command handler از یک endpoint Minimal API ساده است:
app.MapPut("todos/{id:guid}/complete", async (
Guid id,
ICommandHandler<CompleteTodoCommand> handler,
CancellationToken cancellationToken) =>
{
var command = new CompleteTodoCommand(id);
Result result = await handler.Handle(command, cancellationToken);
return result.Match(Results.NoContent, CustomResults.Problem);
})ما ICommandHandler مناسب را مستقیماً به endpoint تزریق میکنیم. نیازی به ISender، لایه mediator یا جستجوی زمان اجرا نیست.
نتیجهگیری 👍
CQRS
به یک فریمورک پیچیده نیاز ندارد.
با چند اینترفیس کوچک، چند کلاس دکوراتور و یک راهاندازی تمیز DI، میتوانید یک پایپلاین ساده و انعطافپذیر برای مدیریت کامندها و کوئریها بسازید. درک، تست و توسعه آن آسان است.
امیدوارم این مطلب مفید بوده باشد.
🔖 هشتگها:
#CSharp #DotNet #CQRS #SoftwareArchitecture #CleanArchitecture #DesignPatterns #BestPractices #MediatR