Я играю с CQRS и библиотекой MediatR, пытаясь изучить некоторые из лучших практик. У меня есть проблема с дублированием кода в обработчиках команд / запросов. Я хотел бы знать, каков наилучший способ обмена logi c между обработчиками.
Пример: у меня есть абстрактный класс Entity, который определяет свойство ID. Все сущности наследуются от этого класса.
public abstract class Entity
{
public long Id { get; private set; }
protected Entity(long id)
{
Id = id;
}
...
}
Затем для каждой сущности я хочу создать запрос GetById. Один из этих запросов выглядит так:
public class GetUserByIdQuery : IRequest<UserDto>
{
public long UserId { get; set; }
public class Handler : IRequestHandler<GetUserByIdQuery, UserDto>
{
private readonly IRepository<User> repository;
private readonly IMapper mapper;
public Handler(IUnitOfWork unitOfWork, IMapper mapper)
{
repository = unitOfWork.GetRepository<User>();
this.mapper = mapper;
}
public async Task<UserDto> Handle(GetUserByIdQuery request, CancellationToken cancellationToken)
{
var user = await repository.FindAsync(request.UserId, null, cancellationToken);
if (user is null)
{
throw new EntityNotFoundException();
}
return mapper.Map<UserDto>(user);
}
}
}
Проблема в том, что этот класс выглядит одинаково для всех сущностей. Без CQRS у меня, вероятно, было бы что-то вроде этого:
public class EntityFinder<TEntity, TDto> where TEntity : Entity
{
private readonly IRepository<TEntity> repository;
private readonly IMapper mapper;
public EntityFinder(IUnitOfWork unitOfWork, IMapper mapper)
{
repository = unitOfWork.GetRepository<TEntity>();
this.mapper = mapper;
}
public async Task<TDto> GetByIdAsync(long id)
{
var entity = await repository.FindAsync(id);
if (entity is null)
{
throw new EntityNotFoundException();
}
return mapper.Map<TDto>(entity);
}
}
Я пытался сделать что-то подобное с запросом и обработчиком generi c, но MediatR не мог найти обработчик (даже когда я пытался зарегистрировать его вручную в DI контейнер).
Каков наилучший способ избежать такого дублирования?