Как избежать дублирования кода в обработчиках запросов MediatR? - PullRequest
0 голосов
/ 05 марта 2020

Я играю с 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 контейнер).

Каков наилучший способ избежать такого дублирования?

1 Ответ

1 голос
/ 05 марта 2020

Можете ли вы попробовать ниже код. Таким образом, вы повторно используете код загрузки и в то же время предоставляете конечную точку для обработки запроса.

public class EntityFinder<TEntity, TDto> where TEntity : Entity
{ ... // Same as your code }

public class GetUserByIdQuery : IRequest<UserDto>
{
    public long UserId { get; set; }
    public class Handler : IRequestHandler<GetUserByIdQuery, UserDto>, EntityFinder<User, UserDto>
    {
        public Handler(IUnitOfWork unitOfWork, IMapper mapper) : base(unitOfWork, mapper)
        { }
        public async Task<UserDto> Handle(GetUserByIdQuery request, CancellationToken cancellationToken)
            => await base.GetByIdAsync(request.UserId);
    }

}
...