Чому вам варто спробувати бібліотеку MediatR для ваших .NET проектів

3 хв. читання

MediatR — бібліотека з відкритим кодом для .NET застосунків, яка реалізовує патерн Mediator (Посередник). ЇЇ автором виступає Jimmy Bogard (автор AutoMapper). У цій статті я спробую описати основні концепції роботи із бібліотекою та один із способів її використання у вашому проекті.

Атомарні контролери

Напевне багато хто з вас стикався із подібною реалізацією API контролера:

public async Task<Response> Create([FromBody] Request request) 
{
    var isValid = _validator.Validate(request);
    if (!isValid) return responseBuilder.BuildBadRequest();
    
    var dto = mapper.Map<ObjectDto, Request>(request);
    
    var result = await repository.Create(dto);
    return responseBuilder.Success(result);
}

На перший погляд із цією реалізацією все гаразд. Ми валідуємо, мапимо, зберігаємо об'єкт. Результат відправляємо у вигляді відповіді. З однієї сторони нічого поганого, але це можна зробити по іншому.

Я завжди притримувався думки, що контролери це всього лиш механізм роутингу. Тобто його завдання - отримати запит і делегувати виконання сервісу. Далі цей сервіс зробить усі необхідні дії та поверне результат. Цей підхід зазвичай називають інкапсуляцією, яку можна реалізувати по іншому.

CQS

Якщо не вникати в деталі, то CQS (Command-Query Separation) — принцип розділення операцій на операції читання та операції запису даних. Це власне саме той підхід, де можна застосувати MediatR, щоб зробити повідомлення та обробники слабозв'язаними.

Багато слів, де код?

Приклад застосунку можна знайти за посиланням. Нижче я поясню ключові моменти використання бібліотеки.

Повідомлення

Коли ви починаєте працювати з MediatR, то перша річ, яку потрібно оголосити, це повідомлення, яке описуватиме поведінку вашої команди чи запиту.

public class GetOrderQuery : IRequest<Order>
{
    public GetOrderQuery(Guid id)
    {
        Id = id;
    }

    public Guid Id { get; }
}

GetOrderQuery описує запит, який використовуватиметься для отримання ордера. Усі повідомлення повинні реалізовувати інтерфейс IRequest<TResponse>, який виступатиме контрактом для обробника повідомлень.

Обробники

Повідомлення у нас є, але для нього потрібен обробник.

public class GetOrderHandler : IRequestHandler<GetOrderQuery, Order>
{
    private readonly IOrderRepository orderRepository;

    public GetOrderHandler(IOrderRepository orderRepository)
    {
        this.orderRepository = orderRepository;
    }

    public Task<Order> Handle(GetOrderQuery request, CancellationToken cancellationToken)
    {
        var result = orderRepository.Get(request.Id);
        return Task.FromResult(result);
    }
}

Усі обробники повинні реалізовувати інтерфейс IRequestHandler<TRequest, TResponse>. Більше деталей про інтерфейс обробника можна знайти за цим посиланням.

Отже, у нас є повідемлення і обробник, що далі?


public class OrdersController : ControllerBase
{
    private readonly IMediator mediator;

    public OrdersController(IMediator mediator) => 
        this.mediator = mediator;

    [HttpGet("{id}")]
    public async Task<Order> Get(Guid id) => 
        await mediator.Send(new GetOrderQuery(id));
}

Все що потрібно, це оголосити контролер, передати йому медіатор і відправити повідомлення. Елементарно ж.

Висновки

Отже ми отримали слабозв'язані повідомлення та обробники, які контролюються медіатором. Також ми отримали атомарний контролер і можливість застосувати CQS підхід. Це звичайно не вирішення усіх проблем розрозбки, але це один із варіантів, який варто спробувати.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 5.6K
Приєднався: 8 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація