воскресенье, 31 мая 2026 г.

MediatR

MediatR: общее описание

MediatR — это лёгкая библиотека для .NET, реализующая паттерн «Посредник» (Mediator Pattern) и облегчающая реализацию паттерна «Команда» (Command Pattern) и «Запрос» (Query Pattern). Её основная задача — уменьшить связность между компонентами приложения, заменяя прямые вызовы на отправку сообщений через посредника.

Основные концепции

  1. Посредник (Mediator) — центральный объект, который принимает сообщения и направляет их соответствующим обработчикам.

  2. Сообщения (Messages) — команды, запросы или уведомления, которые передаются через посредника.

  3. Обработчики (Handlers) — классы, которые обрабатывают конкретные типы сообщений.

Ключевые паттерны, поддерживаемые MediatR

  • Command Pattern — для операций, изменяющих состояние системы (например, «Создать пользователя»).

  • Query Pattern — для операций чтения данных (например, «Получить список пользователей»).

  • Notification Pattern — для событий, на которые могут подписаться несколько обработчиков (например, «Пользователь зарегистрирован»).


MediatR в .NET Core: детальное описание

Установка и настройка

  1. Установите пакет через NuGet:

bash
dotnet add package MediatR

Для интеграции с ASP.NET Core дополнительно установите:

bash
dotnet add package MediatR.Extensions.Microsoft.DependencyInjection
  1. Зарегистрируйте сервисы в Program.cs (для .NET 6+):

csharp
var builder = WebApplication.CreateBuilder(args);

// Регистрация сервисов MediatR
builder.Services.AddMediatR(typeof(Program));

var app = builder.Build();

Основные типы сообщений

  1. Команды (Commands) — операции, изменяющие состояние. Реализуются через IRequest<TResponse>:

csharp
public record CreateUserCommand(string Name, string Email) : IRequest<Guid>;
  1. Запросы (Queries) — операции чтения. Также используют IRequest<TResponse>:

csharp
public record GetUserQuery(Guid Id) : IRequest<UserDto>;
  1. Уведомления (Notifications) — события, на которые может быть несколько подписчиков. Используют INotification:

csharp
public record UserCreatedNotification(Guid UserId, string Email) : INotification;

Создание обработчиков

  1. Для команд и запросов — реализуйте IRequestHandler<TRequest, TResponse>:

csharp
public class CreateUserCommandHandler : IRequestHandler<CreateUserCommand, Guid>
{
    public Task<Guid> Handle(CreateUserCommand request, CancellationToken cancellationToken)
    {
        // Логика создания пользователя
        var userId = Guid.NewGuid();
        // Сохранение в БД и т. д.
        return Task.FromResult(userId);
    }
}
  1. Для уведомлений — реализуйте INotificationHandler<TNotification>:

csharp
public class UserCreatedNotificationHandler : INotificationHandler<UserCreatedNotification>
{
    public Task Handle(UserCreatedNotification notification, CancellationToken cancellationToken)
    {
        // Отправка email, логирование и т. д.
        Console.WriteLine($"User {notification.Email} created");
        return Task.CompletedTask;
    }
}

Использование в контроллерах ASP.NET Core

Внедрите IMediator в контроллер и используйте для отправки сообщений:

csharp
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    private readonly IMediator _mediator;

    public UsersController(IMediator mediator)
    {
        _mediator = mediator;
    }

    [HttpPost]
    public async Task<ActionResult<Guid>> CreateUser(CreateUserCommand command)
    {
        var userId = await _mediator.Send(command);
        return Ok(userId);
    }

    [HttpGet("{id}")]
    public async Task<ActionResult<UserDto>> GetUser(Guid id)
    {
        var query = new GetUserQuery(id);
        var user = await _mediator.Send(query);
        return Ok(user);
    }
}

Расширенные возможности MediatR

Посредники (Behaviors)

Behaviors — это механизмы для добавления кросс‑функциональной логики (логирование, валидация, транзакции) до/после обработки сообщений.

Пример поведения для логирования:

csharp
public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{
    public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
    {
        Console.WriteLine($"Starting {typeof(TRequest).Name}");
        var response = await next();
        Console.WriteLine($"Completed {typeof(TRequest).Name}");
        return response;
    }
}

Регистрация в Program.cs:

csharp
builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));

Валидация с FluentValidation

Можно интегрировать FluentValidation для автоматической валидации команд и запросов:

csharp
public class CreateUserCommandValidator : AbstractValidator<CreateUserCommand>
{
    public CreateUserCommandValidator()
    {
        RuleFor(x => x.Name).NotEmpty();
        RuleFor(x => x.Email).EmailAddress();
    }
}

Поддержка CQRS

MediatR отлично подходит для реализации CQRS:

  • команды (IRequest<T>) — для записи;

  • запросы (IRequest<T>) — для чтения;

  • уведомления (INotification) — для событий.


Преимущества использования MediatR в .NET Core

  1. Снижение связности — компоненты не зависят друг от друга напрямую.

  2. Упрощение тестирования — обработчики легко тестируются изолированно.

  3. Разделение ответственности — чёткое разделение команд и запросов.

  4. Кросс‑функциональная логика — behaviors позволяют добавлять логирование, валидацию и т. д. без изменения бизнес‑логики.

  5. Гибкость — легко добавлять новые команды, запросы и обработчики.

  6. Поддержка событий — уведомления позволяют реализовать event‑driven архитектуру.

  7. Интеграция с DI — полная поддержка встроенного DI‑контейнера .NET Core.

  8. Асинхронность — встроенная поддержка async/await.


Недостатки и ограничения

  1. Дополнительный слой абстракции — может усложнить понимание кода для новичков.

  2. Отладка — сложнее отследить поток выполнения из‑за посредника.

  3. Производительность — небольшой оверхед из‑за дополнительного слоя диспетчеризации.

  4. Переусложнение — для простых CRUD‑приложений может быть избыточным.

  5. Ошибки конфигурации — неправильная регистрация обработчиков приводит к ошибкам во время выполнения.


Практические рекомендации

  1. Структурируйте проект по вертикальным срезам (Vertical Slice Architecture):

Features/
  Users/
    Commands/
      CreateUser/
        CreateUserCommand.cs
        CreateUserCommandHandler.cs
    Queries/
      GetUser/
        GetUserQuery.cs
        GetUserQueryHandler.cs
  1. Используйте behaviors для кросс‑функциональных задач:

    • логирование;

    • валидация;

    • транзакции;

    • кэширование.

  2. Следуйте соглашениям:

    • команды — *Command;

    • запросы — *Query;

    • обработчики — *Handler.

  3. Тестируйте обработчики изолированно — каждый обработчик должен тестироваться отдельно.

  4. Ограничьте доступ к БД — в обработчиках используйте репозитории или сервисы, а не прямое обращение к БД.

  5. Используйте CQRS‑подход — разделяйте команды и запросы, даже если используете один класс IRequest<T>.

  6. Контролируйте размер сообщений — не передавайте избыточные данные в командах и запросах.


Когда использовать MediatR?

Подходит для:

  • средних и крупных приложений с сложной бизнес‑логикой;

  • CQRS‑архитектур;

  • event‑driven систем;

  • микросервисных архитектур;

  • приложений с требованиями к тестируемости и поддерживаемости.

Не подходит для:

  • простых CRUD‑приложений;

  • высокопроизводительных систем с жёсткими требованиями к задержкам;

  • проектов с ограниченными ресурсами и сроками;

  • сценариев, где прямая связь компонентов предпочтительнее.

Комментариев нет:

Отправить комментарий