Command Pattern¶
Command Pattern, veri değiştirme işlemlerini temsil eden bir pattern’dır. MediatR’da command’lar IRequest<T>
interface’ini implemente eder.
Command Özellikleri¶
- Immutable: Command’lar immutable olmalıdır
- Tek Sorumluluk: Her command tek bir iş yapmalıdır
- Validation: Command’lar validate edilebilir olmalıdır
- Idempotent: Mümkünse idempotent olmalıdır
Command Örnekleri¶
Basit Command¶
public class CreateProductCommand : IRequest<int>
{
public string Name { get; set; }
public decimal Price { get; set; }
}
public class CreateProductCommandHandler : IRequestHandler<CreateProductCommand, int>
{
private readonly IProductRepository _repository;
public CreateProductCommandHandler(IProductRepository repository)
{
_repository = repository;
}
public async Task<int> Handle(CreateProductCommand request, CancellationToken cancellationToken)
{
var product = new Product
{
Name = request.Name,
Price = request.Price
};
await _repository.AddAsync(product);
return product.Id;
}
}
Complex Command¶
public class UpdateProductCommand : IRequest
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Description { get; set; }
}
public class UpdateProductCommandHandler : IRequestHandler<UpdateProductCommand>
{
private readonly IProductRepository _repository;
private readonly IUnitOfWork _unitOfWork;
public UpdateProductCommandHandler(
IProductRepository repository,
IUnitOfWork unitOfWork)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<Unit> Handle(UpdateProductCommand request, CancellationToken cancellationToken)
{
var product = await _repository.GetByIdAsync(request.Id);
product.Name = request.Name;
product.Price = request.Price;
product.Description = request.Description;
await _repository.UpdateAsync(product);
await _unitOfWork.SaveChangesAsync();
return Unit.Value;
}
}
Command Best Practices¶
-
Command Validation - FluentValidation kullanın - Validation logic’i behavior’larda olmalı
-
Command Handler Organization - Her handler tek bir repository kullanmalı - Business logic handler içinde olmalı - Cross-cutting concern’ler behavior’lara taşınmalı
-
Error Handling - Özel exception tipleri kullanın - Global exception handling kullanın
-
Testing - Handler’lar unit test edilmeli - Integration testler yazılmalı
Command Pipeline¶
Command’lar pipeline üzerinden geçer:
- Validation
- Authorization
- Logging
- Transaction
- Handler
- Event Publishing
public class CommandPipelineBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
public async Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken cancellationToken)
{
// Pre-processing
var response = await next();
// Post-processing
return response;
}
}