【发布时间】:2020-04-01 16:44:36
【问题描述】:
在我正在开发的应用程序中,我使用 Mediatr 及其管道来处理数据库交互、一些次要业务逻辑、验证等。
我可以在管道中处理访问控制之类的一些检查,因为我使用此处描述的上下文对象https://jimmybogard.com/sharing-context-in-mediatr-pipelines/ 从 ASP.Net 身份转到具有用户信息和声明的自定义上下文对象.
我遇到的一个问题是,由于这个应用程序是多租户的,我需要确保即使一个对象存在,它也属于那个租户,唯一能确保这一点的方法就是抓取该对象从数据库中检查它。在我看来,验证不应该有副作用,所以我不想依赖它来填充上下文对象。但这会将一堆验证推入 Mediatr 处理程序,因为它们检查对象是否存在等等,从而导致大量重复代码。我真的不想多次查询数据库,因为有些查询可能很昂贵。
在实际请求处理程序中进行更复杂的验证的另一个问题是消除本质上的验证错误。目前,如果其中一项检查失败,我会抛出一个ValidationException,然后它会被中间件捕获并变成一个ProblemDetails,并返回给 API 调用者。这基本上是流控制的异常,无论如何验证失败都不是“异常”。
我对如何解决这个问题的想法是:
在管道中的某处,当我构建上下文时,包括尝试从数据库中获取所需的对象。如果其中任何一个为空,则验证将失败。这似乎会使测试变得更加困难,并且需要以某种方式装饰请求(或使用反射),以便管道可以知道尝试加载这些对象。
在验证器中有查询,但使用某种缓存感知存储库,因此当稍后查询相同的对象时,它是从缓存中提供的,而不是从数据库中提供的。处理程序还将使用此缓存感知存储库(当前处理程序直接与 EF Core DbContext 交互以进行查询)。然后,这增加了缓存失效的问题,无论如何我将不得不在某个时候处理(相当多的项目很少修改)。为了测试,可以注入一个实际上不缓存任何东西的虚拟缓存对象。
使来自请求的所有响应实现一个接口(或扩展一个抽象类),该接口具有验证信息、一般成功标志等。这可以通过 API 直接返回,或者具有一些转换失败的管道进入
ProblemDetails。这将为每个响应和处理程序添加一些样板,但避免了流控制等异常以及其他选项中的缓存/反射问题。
假设 1 和 2 任何种类的竞争条件都不是问题。对象不会更改所有者,并且出于审计/会计目的而实际上很少从数据库中删除事物。
我知道没有真正的一刀切可以解决此类问题,但我想知道是否还有其他我遗漏的选项,或者任何具有类似管道的人在使用时遇到的任何长期可维护性问题这些列出的选项。
【问题讨论】:
标签: asp.net-core fluentvalidation mediatr