Обобщённый Query в Mediatr

120
26 марта 2021, 09:10

Столкнулся с вот какой проблемой переделывая репозиторий на CQS.

Был метод выбирающий из базы контакты по предикату и сортирующий по определённому полю:

public async Task<IEnumerable<Contact>> GetAsync(Expression<Func<Contact, bool>> predicate, Expression<Func<Contact, TOrderKey>> orderBy, CancellationToken cancellationToken)
{
    return await this.ApplicationDbContext.Contacts
                     .Include(x => x.ApplicationUser.City)
                     .Where(predicate)
                     .OrderBy(orderBy)
                     .AsNoTracking()
                     .ToArrayAsync(cancellationToken);
}

Работает, всё окей. Стал переносить в Mediatr - понял, что не понимаю, как мне написать обобщённый запрос (никогда не делал) и что-то не нахожу примеров.

Я так понимаю, что должно быть как-то так:

Запрос:

public class Query<TOrderKey> : IRequest<IEnumerable<Contact>>
    where TOrderKey : class
{
    public Query(Expression<Func<Contact, bool>> predicate, Expression<Func<Contact, TOrderKey>> orderBy)
    {
        this.Predicate = predicate;
        this.OrderBy = orderBy;
    }
    public Expression<Func<Contact, bool>> Predicate { get; }
    public Expression<Func<Contact, TOrderKey>> OrderBy { get; }
}

Обработчик:

public class Handler<TOrderKey> : BaseHandler, IRequestHandler<Query<TOrderKey>, IEnumerable<Contact>>
    where TOrderKey : class
{
    public Handler(ApplicationDbContext applicationDbContext)
        : base(applicationDbContext)
    {
    }
    public async Task<IEnumerable<Contact>> Handle(Query<TOrderKey> request, CancellationToken cancellationToken)
    {
        return await this.ApplicationDbContext.Contacts
                         .Include(x => x.ApplicationUser.City)
                         .Where(request.Predicate)
                         .OrderBy(request.OrderBy)
                         .AsNoTracking()
                         .ToArrayAsync(cancellationToken);
    }
}

И оно даже компилируется... но падает в рантайме при попытке вызова с ошибкой:

Expression<Func<Contact, bool>> expr = x => x.OwnerId == request.UserID;
if (request.Filter.CityId != null)
{
    Expression<Func<Contact, bool>> exprCity = x => x.ApplicationUser.CityId == request.Filter.CityId;
    expr = expr.AndAlso(exprCity);
}
if (!string.IsNullOrWhiteSpace(request.Filter.SearchText))
{
    Expression<Func<Contact, bool>> exprText = x => x.DisplayName.Contains(request.Filter.SearchText) || x.Notes.Contains(request.Filter.SearchText);
    expr = expr.AndAlso(exprText);
}
return this.Mediator.Send(new Contacts.List.Query<string>(expr, x => x.DisplayName));

An unhandled exception occurred while processing the request.

InvalidOperationException: Handler was not found for request of type MediatR.IRequestHandler2[Application.Contacts.List.Query1[System.String],System.Collections.Generic.IEnumerable`1[Domain.Models.Contact]]. Register your handlers with the container. See the samples in GitHub for examples.

MediatR.Internal.RequestHandlerBase.GetHandler(ServiceFactory factory)

Регистрация mediatr в Startup.cs самая обычная, все остальные обработчики находятся без проблем:

services.AddMediatR(typeof(Application.City.Create.Command).GetTypeInfo().Assembly);

Здесь указывается, что для того, чтобы generic handler работали - нужно в первую очередь, чтобы применённый в проекте DI контейнер поддерживал динамическую диспетчеризацию (polymorphic dispatch). У меня используется рекомендованный для .net core MediatR.Extensions.Microsoft.DependencyInjection и у него такая поддержка заявлена (см. на заглавной репозитория: "Supports generic variance of handlers.")

Однако у меня обобщённый не только handler, но и query.

Как правильно делать подобные запросы в mediatr?

READ ALSO
Чтение json и добавление в базу данных mssql

Чтение json и добавление в базу данных mssql

Такой вопросЕсть база данных в json формате

80
Множественное использование count в Linq C#

Множественное использование count в Linq C#

Встала задача сделать выборку нескольких Count-значений из 2-ух таблиц базы данныхРешил сделать это с помощью лямбда-выражений

69
C# Закрытие окна

C# Закрытие окна

Извиняюсь за такой тупой вопрос, но я просто разбит, что не могу понятьПрограмма работает так, сначала запускается форма с логотипом, а потом...

87
Аргументы в функции Replace

Аргументы в функции Replace

Возможно ли в функции Replace в качестве одно из аргумента использовать регулярное выражение? Если да, то какой синтаксис?

84