CQRS (Command Query Responsibility Segregation) to wzorzec projektowy, który rozdziela operacje zapisu danych (komendy) od operacji odczytu danych (zapytania) w aplikacji. Wzorzec ten pomaga w lepszym zarządzaniu i skalowaniu systemów, które mają różne wymagania dotyczące zapisu i odczytu danych. W ASP.NET Core Web API często korzysta się z tego wzorca w połączeniu z biblioteką MediatR do implementacji.

CQRS skupia się na dwóch głównych obszarach:

  1. Komendy (Commands): Komendy to żądania zmiany stanu aplikacji. Obejmują operacje, które modyfikują dane w bazie danych lub w innych źródłach. Na przykład, dodawanie nowego produktu do bazy danych jest komendą.
  2. Zapytania (Queries): Zapytania to żądania odczytu danych. Służą do pobierania informacji z aplikacji, ale nie zmieniają jej stanu. Na przykład, pobieranie listy produktów z bazy danych jest zapytaniem.

MediatR w ASP.NET Core

MediatR to biblioteka w ASP.NET Core, która ułatwia implementację wzorca CQRS. Jest to narzędzie do obsługi komend i zapytań oraz rozgłaszania ich do odpowiednich obszarów aplikacji.

Zastosowanie MediatR w ASP.NET Core Web API:

Aby wykorzystać bibliotekę MediatR w ASP.NET Core Web API, wykonujemy kilka kroków:

  1. Instalacja biblioteki MediatR:

    Najpierw instalujemy bibliotekę MediatR i inne powiązane paczki, takie jak MediatR.Extensions.Microsoft.DependencyInjection.

    dotnet add package MediatR
    dotnet add package MediatR.Extensions.Microsoft.DependencyInjection
    
  2. Tworzenie komend i zapytań:

    Tworzymy klasy reprezentujące komendy i zapytania. Na przykład:

    public class CreateProductCommand : IRequest<Product>
    {
        // Dane potrzebne do stworzenia produktu
    }
    
    public class GetProductsQuery : IRequest<List<Product>>
    {
        // Opcjonalne dane do zapytania
    }
    
  3. Obsługa komend i zapytań:

    Tworzymy obsługi komend i zapytań. Te obsługi zawierają logikę biznesową i są odpowiedzialne za modyfikację stanu aplikacji (dla komend) lub odczyt danych (dla zapytań).

    // Obsługa komendy
    public class CreateProductCommandHandler : IRequestHandler<CreateProductCommand, Product>
    {
        private readonly IProductRepository _productRepository;
    
        public CreateProductCommandHandler(IProductRepository productRepository)
        {
            _productRepository = productRepository;
        }
    
        public async Task<Product> Handle(CreateProductCommand request, CancellationToken cancellationToken)
        {
            var product = new Product
            {
                Name = request.Name,
                Price = request.Price
            };
    
            await _productRepository.AddProduct(product);
    
            return product;
        }
    }
    
    // Obsługa zapytania
    public class GetProductsQueryHandler : IRequestHandler<GetProductsQuery, List<Product>>
    {
        private readonly IProductRepository _productRepository;
    
        public GetProductsQueryHandler(IProductRepository productRepository)
        {
            _productRepository = productRepository;
        }
    
        public async Task<List<Product>> Handle(GetProductsQuery request, CancellationToken cancellationToken)
        {
            var products = await _productRepository.GetProducts();
            return products.ToList();
        }
    }
    
  4. Rejestracja MediatR w aplikacji:

    Rejestrujemy MediatR w kontenerze DI (Dependency Injection) w metodzie ConfigureServices klasy Startup.cs.

    services.AddMediatR(typeof(Startup));
    
  5. Kontrolery:

    W kontrolerach możemy wstrzykiwać interfejs IMediator i używać go do wysyłania komend i zapytań do obsługi.

    [ApiController]
    [Route("api/[controller]")]
    public class ProductsController : ControllerBase
    {
        private readonly IMediator _mediator;
    
        public ProductsController(IMediator mediator)
        {
            _mediator = mediator;
        }
    
        [HttpPost]
        public async Task<IActionResult> CreateProduct(CreateProductCommand command)
        {
            var product = await _mediator.Send(command);
            return Ok(product);
        }
    
        [HttpGet]
        public async Task<IActionResult> GetProducts()
        {
            var query = new GetProductsQuery();
            var products = await _mediator.Send(query);
            return Ok(products);
        }
    }
    

Dzięki użyciu MediatR w ASP.NET Core Web API możemy łatwo wdrożyć wzorzec CQRS, co ułatwia zarządzanie komendami i zapytaniami w naszej aplikacji. MediatR pomaga również w zachowaniu przejrzystości i organizacji kodu, dzięki czemu jest to przydatne narzędzie do rozwijania bardziej zaawansowanych i skalowalnych systemów.

Materiały

.Net Core Web API with CQRS / MediatR

GitHub - jbogard/MediatR: Simple, unambitious mediator implementation in .NET

CQRS and MediatR In ASP.NET Core