具有通用处理程序和查询的 Mediatr

Bry*_*yan 6 c# covariance contravariance mediator mediatr

我正在使用 Mediatr 开发 ASP.NET Core 2.2 Web API 应用程序。

我有一个看起来像这样的处理程序 -

public class MyQueryHandler<T> : IRequestHanlder<MyQuery<T>, IQueryable<T>>
{
   public Task<IQueryable<T>> Handle(MyQuery<T> myquery, CancellationToken cancellationToken)
   {
       //perform query

       IQueryable<T> models = someDatabaseQuery.ProjectTo<T>();
   }       
}
Run Code Online (Sandbox Code Playgroud)

这是查询 -

public class MyQuery<T> : IRequest<IQueryable<T>>
{
   //some properties
}
Run Code Online (Sandbox Code Playgroud)

当我尝试提出这样的请求时 -

var result = await _mediator.Send(new MyQuery<SomeModel> {/* set the properties on the query */})
Run Code Online (Sandbox Code Playgroud)

我得到一个例外 -

An unhandled exception occurred while processing the request.

InvalidOperationException: Handler was not found for request of type MediatR.IRequestHandler`2[MyQuery`1[SomeModel],System.Linq.IQueryable`1[SomeModel]]. Register your handlers with the container. See the samples in GitHub for examples.
Run Code Online (Sandbox Code Playgroud)

我花了几个小时尝试了很多东西,但没有一个起作用。我什至厌倦了按照 Mediator github 存储库中提供的示例,将 Autofac 与服务集合一起使用。

Gol*_*Age 2

每个查询应该有一个具体的类型/平面结构,以便它的处理程序可以在运行时由依赖注入容器轻松注册。我相信按照您给出的示例注册通用查询处理程序是不可能的,因为 DI 容器在注册通用类型时可能会出现问题。我相信创建一种行为是你应该做的正确的事情。Query它可以让您在一个地方处理所有查询或命令,因此您可以在点击给定/的处理程序之前运行一些额外/通用逻辑,例如日志记录等Command

编辑

在处理程序中,我使用自动映射器投影来限制从相关数据库表中查询的内容。让调用者告诉查询并依次告诉处理程序所需数据的形状。

为了限制从数据库查询的内容,我将使用为每个实体创建查询和查询处理程序的方法。我认为进行这样的分离是有意义的,因为从安全角度来看,您可能只想授予特定用户组的访问权限来运行给定的查询。

因此,例如实体的示例Order如下所示。

public class OrderDto
{
    public string Name { get; set; }

    public int Amount { get; set; }
}

public class FilterOrdersQuery : IRequest<List<OrderDto>>
{
    public string Filter { get; set; }
}

public class FilterOrdersQueryHandler : IRequestHandler<FilterOrdersQuery, List<OrderDto>>
{
    public Task<List<OrderDto>> Handle(FilterOrdersQuery notification, CancellationToken cancellationToken)
    {
        var dataSource = new List<OrderDto>(){
            new OrderDto()
            {
                Name = "blah",
                Amount = 65
            },
            new OrderDto()
            {
                Name = "foo",
                Amount = 12
            },
        };

        var result = dataSource
            .Where(x => x.Name.Contains(notification.Filter))              
            .ToList();

        return Task.FromResult(result);
    }
}
Run Code Online (Sandbox Code Playgroud)

这只是一个简单的示例,展示了如何过滤给定的实体并返回过滤对象的列表。您还可以添加分页、OrderBy 等逻辑。