CQRS中的业务规则验证器和命令处理程序

36
我刚接触CQRS,正在试图理解写操作(领域)中的业务规则验证。我知道应该在客户端验证方面执行有效日期(必填字段、字符串长度、有效电子邮件等)以及基于业务规则/业务域的验证应在领域端执行。实际上,客户端验证规则也应该适用于领域中的命令,因为我们不信任用户。
所以,我们有一个有效的命令(AddEmailToCustomer),并且在命令上调用了命令处理程序。以下是我的验证方法:
1. 在命令处理程序中创建两个命令验证器的实例。 2. 第一个验证器验证命令数据,同样符合客户端验证(必填字段、有效电子邮件等)。 3. 第二个验证器根据第二个验证器内部的逻辑对数据进行验证。比如,“该客户是否活跃”,或其他事项。我知道更改电子邮件不适合这里,但这不重要。重要的是这里有业务验证。 4. 我们查看由Validator.Validate(ICommand cmd)返回的ValidationResult,然后查找其中的错误。 5. 我们将不会从存储库获取客户端来调用AR上的UpdateEmail方法。那么此时我们该怎么做?
在命令处理程序中抛出异常并添加这些错误吗? 将命令发送到错误队列或其他地方吗? 是否使用Bus.Reply响应并返回错误代码?如果是,我该如何处理错误消息? 如何将这些错误通知给用户?我知道我可以稍后通过电子邮件发送它们,但在Web场景中,我可以在命令中发送请求ID(或使用消息ID),并使用请求ID轮询响应,并向用户显示错误消息。
感谢您的指导。

2
所有的验证应该在命令之前完成,当你发出命令时,你假设命令不会失败。 - Phill
在Web应用程序的控制器中,在我发送命令到总线之前,我需要进行验证吗?如果需要,该如何实现?调用验证器服务或类似的东西吗? - kind_robot
比我最初想象的更简单 :) 谢谢 - kind_robot
2
@Phill:在发送命令之前,您将如何验证聚合物是否发生了另一个冲突的修改? - quentin-starin
@qes - 你能给个例子吗?两条消息同时发送的情况非常罕见。使用CQRS,你正在处理特定的服务,比如OrderService,不会有两个不同的消息同时发送到同一个订单,其中一个可能会使另一个无效。如果你正在更新客户信息,在CustomerCareService中,我不确定什么情况下会有两个东西在更新同一个客户信息... - Phill
显示剩余2条评论
1个回答

44

需要知道的是,命令可能在发送到处理程序后被拒绝。

至少,您可能会遇到并发违规,直到触摸聚合根时才能检测到。

但是,实体外部可能发生的验证只是简单的验证。不仅包括字符串长度、数字范围、正则表达式匹配等,还包括可以通过查询或视图合理满足的验证,例如集合中的唯一性。重要的是要记住,涉及物化视图的验证可能是最终一致性的,这是命令可能会从聚合内部,在命令处理程序中被拒绝的另一个原因。也就是说,为了预防这种情况,我经常使用读模型来驱动只允许有效操作的用户界面选择。

不能在实体外部发生的验证是您的业务逻辑验证。该验证取决于其运行的上下文(请参见 Udi Dahan 的 Clarified CQRS)。

业务逻辑应该在单独的验证服务中。它应该在您的领域中。

此外,我认为在 UI 中发生的验证应该在命令处理程序中进行重新检查,而是在领域中进行。该验证旨在防止对领域的破坏--如果它没有在领域外执行,则领域仍然受到无效参数的影响。

使用命令处理程序来复制此验证只是一种约定。如果没有其他前端发送命令,则它是一个无用的副本。如果有多个前端,则只是放置必要的重复验证的选择之一,在这些情况下,我更喜欢在领域中处理它。

最后,您需要将从处理程序内部拒绝的命令上升。我尽可能使用异常来完成此操作。


5
您如何向用户传达命令被拒绝的错误信息?是通过电子邮件、带请求ID的回调等方式进行通知呢? - kind_robot
@gandalf:我想这会取决于客户端的类型。如果您有一个WPF客户端,那么回调可能是最简单的方法。如果您有一个MVC客户端,那我就不确定了...也许你可以在命令中传递2个URL:一个用于成功时获取,另一个用于失败时获取。然后服务可以获取相应的URL,您可以在客户端执行适当的逻辑。 - Roy Dictus
2
我同意qes所说的。唯一不同意的是将验证逻辑放在领域内,即使你有多个前端。归根结底,命令处理程序与您的领域一样重要(或者至少是唯一的入口)。但不要只听我的话:http://tinyurl.com/66kaorv - Yves Reynhout
1
可能会有来自领域的规范和来自其他领域的规范或限制。这不是一个信任问题吗?信任边界在哪里?由于该领域可能被错误地使用并可能在不同的应用程序中被重复使用,因此我认为领域模型周围存在着信任边界。因此,我认为领域规范的验证属于领域内。其他原因(例如持久性)的规范验证属于相应的层,因为有另一个保护它的信任边界。 - user573215
2
如果有人发现这个有用的话,我已经更深入地探讨了在CQRS系统中的命令验证。你可以在这里找到它:如何在CQRS应用程序中验证命令 - Codescribler
@Codescribler,你能看一下我的问题吗?链接在这里:https://softwareengineering.stackexchange.com/questions/372338/zero-arguement-constructors-and-always-valid-entities?它与这个问题类似。 - w0051977

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接