使用 MediatR 链接处理程序

Posted

技术标签:

【中文标题】使用 MediatR 链接处理程序【英文标题】:Chaining Handlers with MediatR 【发布时间】:2020-01-24 19:10:17 【问题描述】:

我们正在使用 MediatR 为我们的 dotnet 核心 WebAPI 后端实现“管道”,试图遵循 CQRS 原则。

我无法决定是否应该尝试实现 IPipelineBehavior 链,或者是否应该构造一个新的请求并从我的 Handler 方法中调用 MediatR.Send 更好(对于请求)。

场景本质上是这样的:

用户请求要执行的操作,即删除某些内容 我们必须检查该东西是否被其他人使用 我们必须在数据库中将该内容标记为已删除 我们必须实际从文件系统中删除文件。

选项1是我们现在拥有的:一个DeleteRequest,由一个类处理,其中Handler检查它是否正在使用,将其标记为已删除,然后发送一个新的@ 987654323@带参数删除。

选项2是我正在考虑的:一个DeleteRequest,它实现了标记接口IRequireCheckIStartTask,带有一个运行的管道:

    IPipelineBehavior<IRequireCheck>先检查一下有没有被使用, IPipelineBehavior<DeleteRequest> 将数据库中的内容标记为已删除,并 IPipelineBehavior<IStartTask> 启动任务。

我还没有完全弄清楚选项 2 会是什么样子,但这是一般的想法。

我想我主要想知道在 TRequest1 的处理程序中调用 MediatR.Send(TRequest2) 是否是代码异味。

【问题讨论】:

您是否能够实施您的第二个选项?我发现有关 Pipelines and Behaviors 的文档在为我提供足够的上下文以将它们转换为我的情况方面缺乏,这与您的 #2 类似。 我们还没有实现该功能,它还不是优先事项,但很快就会实现。我学到了一些关于注册管道处理程序的有趣的东西,所以它使这更可行。我们在身份验证、审计日志记录和其他一些交叉问题上做类似的事情。 本质上,我们使用反射来注册标记接口类的处理程序,因此它们被正确注册为仅作为相应请求或响应类型的前置或后置处理器运行。我们将其用于 IAddToAuditLog 等标记接口。 【参考方案1】:

如果这些是您设置的选项 - 我说的是选项 2。从现有 Mediatr 处理程序内部发送请求可以被视为代码异味。你隐藏了副作用并打破了单一责任原则。您还将您的请求耦合在一起,您应该尽量避免无法在另一种请求之前发送一种类型的请求的情况。

但是,我认为可能还有其他选择。如果没有事先验证和标记就无法发生删除请求,您可以为您的TaskStartRequest 使用预处理器 (example here)。这样你就可以有一个请求来完成你需要的一切。这甚至可以通过简单地利用现有的 Mediatr 模式来反映您的管道示例。

【讨论】:

第一次或第二次检查失败的情况,我们将如何停止其余的处理?在 Pipeline 实现中,我认为我必须调用 next() 才能继续处理,所以如果 next() 失败,我可以跳过调用。 嗯,这很好。在过去,我抛出了一个异常。因此,如果我们要删除的项目不存在,我会抛出一个在中间件中处理的自定义异常,从而导致 404。如果您不想导致使用异常,我认为您的管道想法仍然更好。然后你就可以毫无例外地控制执行。【参考方案2】:

是否需要将任务分解为多个Handlers?也许我错过了mediatr 的重点。这还不够吗?

public async Task<Result<IFailure,ISuccess>> Handle(DeleteRequest request)

  var thing = await this.repo.GetById(request.Id);

  if (thing.IsBeignUsed())
  
    return Failure.BeignUsed();
  
  var deleted = await this.repo.Delete(request.Id);
  return deleted ? new Success(request.Id) : Failure.DbError();

【讨论】:

这个选项假设thing能够确定它是否被使用;情况并非总是如此。 在我们的例子中,这不仅仅是从 repo 中删除的问题,还需要启动一个删除文件的任务。任务是使用不同的处理器启动的,就像我提到的那样,我不喜欢从处理程序的主体发送不同的请求。 发送通知或请求开始任务是否有意义?类似问题请见github.com/jbogard/MediatR/issues/237。

以上是关于使用 MediatR 链接处理程序的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 FluentAssertions 在 XUnit 中测试 MediatR 处理程序

MediatR 错误:向容器注册您的处理程序

使用 MediatR 时可以让一个处理程序调用另一个处理程序吗?

如何为 ASP.NET Core 注册和使用 MediatR 管道处理程序?

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

如何使用FluentAssertions在XUnit中测试MediatR处理程序