Merhaba arkadaşlar, bugün sizlere cqrs, mediator pattern(MediatR package),AutoMapper ve repository kullanarak ufak bir Crud örneği yapacağım.
Mediator pattern
Bence bu patterni en iyi açıklayan yapı en bilinen örneği. Uçaklar arası iletişimi sağlayan kule olarak düşünülebilir yani uçakların birbirleri ile iletişimi yoktur, hepsinin iletişimi kule üzerinden sağlanır. Mediator patternde buradaki kule yapısını kullanmamızı sağlar.
Cqrs (Command Query Responsibility Segregation)
Bu pattern command ve querylerin yani datayı değiştiren sorgular (Create,Update,Delete) ile listeleme (Read) sorgularının ayrılması prensibi üzerine kurulmuştur. “docs.microsoft.com” adresinde bu patternin avantajı aşağıdaki şekilde özetlenmiştir.
“CQRS uygulamak performansını, ölçeklenebilirliğini ve güvenliğini en üst düzeye çıkarabilir. CQRS’ye geçirilerek oluşturulan esneklik, sistemin zaman içinde daha iyi gelişmesine olanak tanır.”
https://www.youtube.com/watch?v=KIhMeJ-jYME
Command ve query aynı storedan beslenebilir. Bu kullanımda store yönetimi daha kolay olsa da ölçekleme ve esneklik tarafında bir kayıp olabilir.

Event Sourcing ile beraber cqrs pattern kullanılabilir. Doğru bir yapıda kurulduğu zaman çok avantajlı kullanımlar sunmaktadır.
Aşağıdaki senaryolarda Cqrs kullanılabilir.
- Birçok kullanıcının aynı verilere paralel olarak eriştiği işbirliğine dayalı etki alanları
- Yazma ve Okuma logicleri ve aşamaları ayrıştırmak isteniyorsa
- Okuma Sayısının yazma sayısından çok fazla olduğu durumlarda
- Karmaşıklığa göre yazma ve okuma ekiplerinin ayrıldığı durumlarda
- Modelin birden fazla sürümünü içerebildiği ya da iş kurallarının düzenli olarak değiştiği senaryolarda.
Aşağıdaki durumlarda kullanılması önerilmez
- Basit bir etki alanı varsa
- Kompleks olmayan iş kuralları varsa
- Basit Crud operasyonları ile çözülebilecek yapılarda
“CQRS modelini yalnızca en çok değer katacağını düşündüğünüz belirli sistem bölümlerine uygulayın.” -docs.microsoft.com
Örneğimizin daha basit ve anlaşılır olması adına tek proje altında işlemleri gerçekleştireceğim. Şimdi örneğimize gelelim öncelikle MediatR ve MediatR.Extensions.Microsoft.DependencyInjection paketlerimizi kuralım. Dummy Entity ve dummy repositorimizi ekleyerek singleton olarak register edelim.
////Program.cs builder.Services.AddSingleton<IProductRepository, ProductRepository>(); ///Repo public class Product { public Guid Id { get; set; } public string Name { get; set; } public DateTime CreateDate { get; set; } } public interface IProductRepository { public Product GetProductById(Guid id); } public class ProductRepository : IProductRepository { List<Product> Products; public ProductRepository() { Products = new List<Product> { new Product { Id = Guid.NewGuid(),Name="Phone",CreateDate = DateTime.UtcNow }, new Product { Id = Guid.NewGuid(),Name="Laptop",CreateDate = DateTime.UtcNow }, new Product { Id = Guid.NewGuid(),Name="TV",CreateDate = DateTime.UtcNow }, }; } public Product GetProductById(Guid id) { var product = Products.FirstOrDefault(p => p.Id == id); return product; } }
Request ve Response Modellerimizi oluşturalım.
public class GetProductByIdQueryRequest : IRequest<GetProductByIdQueryResponse> { public Guid Id { get; set; } } public class GetProductByIdQueryResponse { public Guid Id { get; set; } public string Name { get; set; } public DateTime CreateDate { get; set; } }
Projemize Automapper paketini ekleyerek modellerimizi entitymize mapleyelim.
public class RegisterMapper : Profile { public RegisterMapper() { CreateMap<Product, GetProductByIdQueryResponse>(); } } ///////////Program.cs #region Automapper register var config = new MapperConfiguration(conf => { conf.AddProfile<RegisterMapper>(); }); builder.Services.AddScoped(s => config.CreateMapper()); #endregion
Şimdi ilgili metoda yönlendirecek handlerımızı yazalım.
public class GetProductByIdQueryHandler : IRequestHandler<GetProductByIdQueryRequest, GetProductByIdQueryResponse> { private readonly IProductRepository _productRepository; private readonly IMapper _mapper; public GetProductByIdQueryHandler(IProductRepository productRepository, IMapper mapper) { _productRepository = productRepository; _mapper = mapper; } public Task<GetProductByIdQueryResponse> Handle(GetProductByIdQueryRequest request, CancellationToken cancellationToken) { var product = _productRepository.GetProductById(request.Id); var mapProduct = _mapper.Map<GetProductByIdQueryResponse>(product); return Task.FromResult(mapProduct); } }
Artık controller içerisinde mediator servisi inject edip kullanmamız kaldı. Bunun için program.cs / startup altına servisimizi register edelim.
////Program.cs builder.Services.AddMediatR(typeof(Program)); ///Controller [ApiController] [Route("api/[controller]")] public class ProductsController : ControllerBase { private readonly IMediator _mediator; public ProductsController(IMediator mediator) { _mediator = mediator; } #region Queries [HttpGet("{id}")] public async Task<IActionResult> Get(Guid id) => Ok(await _mediator.Send(new GetProductByIdQueryRequest { Id = id })); #endregion }
Evet arkadaşlar basit bir şekilde Cqrs, MediatR, Repository ve AutoMapper’ı bir arada kullandık. Projeyi daha detaylı incelemek ve diğer operasyonlarında kodunu incelemek isterseniz github reposunu ziyaret edebilirsiniz.