MediatR: общее описание
MediatR — это лёгкая библиотека для .NET, реализующая паттерн «Посредник» (Mediator Pattern) и облегчающая реализацию паттерна «Команда» (Command Pattern) и «Запрос» (Query Pattern). Её основная задача — уменьшить связность между компонентами приложения, заменяя прямые вызовы на отправку сообщений через посредника.
Основные концепции
Посредник (Mediator) — центральный объект, который принимает сообщения и направляет их соответствующим обработчикам.
Сообщения (Messages) — команды, запросы или уведомления, которые передаются через посредника.
Обработчики (Handlers) — классы, которые обрабатывают конкретные типы сообщений.
Ключевые паттерны, поддерживаемые MediatR
Command Pattern — для операций, изменяющих состояние системы (например, «Создать пользователя»).
Query Pattern — для операций чтения данных (например, «Получить список пользователей»).
Notification Pattern — для событий, на которые могут подписаться несколько обработчиков (например, «Пользователь зарегистрирован»).
MediatR в .NET Core: детальное описание
Установка и настройка
Установите пакет через NuGet:
dotnet add package MediatR
Для интеграции с ASP.NET Core дополнительно установите:
dotnet add package MediatR.Extensions.Microsoft.DependencyInjection
Зарегистрируйте сервисы в
Program.cs(для .NET 6+):
var builder = WebApplication.CreateBuilder(args);
// Регистрация сервисов MediatR
builder.Services.AddMediatR(typeof(Program));
var app = builder.Build();
Основные типы сообщений
Команды (Commands) — операции, изменяющие состояние. Реализуются через
IRequest<TResponse>:
public record CreateUserCommand(string Name, string Email) : IRequest<Guid>;
Запросы (Queries) — операции чтения. Также используют
IRequest<TResponse>:
public record GetUserQuery(Guid Id) : IRequest<UserDto>;
Уведомления (Notifications) — события, на которые может быть несколько подписчиков. Используют
INotification:
public record UserCreatedNotification(Guid UserId, string Email) : INotification;
Создание обработчиков
Для команд и запросов — реализуйте
IRequestHandler<TRequest, TResponse>:
public class CreateUserCommandHandler : IRequestHandler<CreateUserCommand, Guid>
{
public Task<Guid> Handle(CreateUserCommand request, CancellationToken cancellationToken)
{
// Логика создания пользователя
var userId = Guid.NewGuid();
// Сохранение в БД и т. д.
return Task.FromResult(userId);
}
}
Для уведомлений — реализуйте
INotificationHandler<TNotification>:
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 в контроллер и используйте для отправки сообщений:
[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 — это механизмы для добавления кросс‑функциональной логики (логирование, валидация, транзакции) до/после обработки сообщений.
Пример поведения для логирования:
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:
builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
Валидация с FluentValidation
Можно интегрировать FluentValidation для автоматической валидации команд и запросов:
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
Снижение связности — компоненты не зависят друг от друга напрямую.
Упрощение тестирования — обработчики легко тестируются изолированно.
Разделение ответственности — чёткое разделение команд и запросов.
Кросс‑функциональная логика — behaviors позволяют добавлять логирование, валидацию и т. д. без изменения бизнес‑логики.
Гибкость — легко добавлять новые команды, запросы и обработчики.
Поддержка событий — уведомления позволяют реализовать event‑driven архитектуру.
Интеграция с DI — полная поддержка встроенного DI‑контейнера .NET Core.
Асинхронность — встроенная поддержка
async/await.
Недостатки и ограничения
Дополнительный слой абстракции — может усложнить понимание кода для новичков.
Отладка — сложнее отследить поток выполнения из‑за посредника.
Производительность — небольшой оверхед из‑за дополнительного слоя диспетчеризации.
Переусложнение — для простых CRUD‑приложений может быть избыточным.
Ошибки конфигурации — неправильная регистрация обработчиков приводит к ошибкам во время выполнения.
Практические рекомендации
Структурируйте проект по вертикальным срезам (Vertical Slice Architecture):
Features/
Users/
Commands/
CreateUser/
CreateUserCommand.cs
CreateUserCommandHandler.cs
Queries/
GetUser/
GetUserQuery.cs
GetUserQueryHandler.cs
Используйте behaviors для кросс‑функциональных задач:
логирование;
валидация;
транзакции;
кэширование.
Следуйте соглашениям:
команды —
*Command;запросы —
*Query;обработчики —
*Handler.
Тестируйте обработчики изолированно — каждый обработчик должен тестироваться отдельно.
Ограничьте доступ к БД — в обработчиках используйте репозитории или сервисы, а не прямое обращение к БД.
Используйте CQRS‑подход — разделяйте команды и запросы, даже если используете один класс
IRequest<T>.Контролируйте размер сообщений — не передавайте избыточные данные в командах и запросах.
Когда использовать MediatR?
Подходит для:
средних и крупных приложений с сложной бизнес‑логикой;
CQRS‑архитектур;
event‑driven систем;
микросервисных архитектур;
приложений с требованиями к тестируемости и поддерживаемости.
Не подходит для:
простых CRUD‑приложений;
высокопроизводительных систем с жёсткими требованиями к задержкам;
проектов с ограниченными ресурсами и сроками;
сценариев, где прямая связь компонентов предпочтительнее.