35

我是 CQRS 的新手,我想了解写入端(域)内的业务规则验证。我知道客户端验证应该根据有效日期(必填字段、字符串长度、有效电子邮件等)进行,业务规则/业务域相关验证应该在域端进行。实际上,同样的客户端验证规则也应该应用于域中的命令,因为我们不信任用户。

因此,我们有一个有效的命令 (AddEmailToCustomer),并且在该命令上调用了命令处理程序。这是我的验证方法。

  1. 在命令处理程序中创建两个命令验证器的实例。
  2. 第一个验证与客户端验证相同的命令数据(必填字段、有效电子邮件等)
  3. 第二个验证器根据第二个验证器内的逻辑验证数据。诸如“此客户是否活跃”之类的东西,或者其他什么。我知道不断变化的电子邮件不适合这里,但这并不重要。重要的是这里有一个业务验证。
  4. 我们查看 Validator.Validate(ICommand cmd) 返回的 ValidationResult 发现有错误
  5. 我们不会让存储库中的客户调用 AR 上的 UpdateEmail 方法。那么此时我们该怎么做呢?

我是否在命令处理程序中抛出异常并在那里添加这些错误?我是否将命令发送到错误队列或其他地方?我是否会回复 Bus.Reply 之类的内容并返回错误代码?如果是这样,我该如何处理错误消息?如何将这些错误传达给用户?我知道我可以稍后通过电子邮件发送给他们,但在 Web 场景中,我可以在命令中发送请求 ID(或使用消息 ID),并使用请求 ID 轮询响应并向用户显示错误消息。

感谢您的指导。

谢谢

4

1 回答 1

43

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

至少,您可能会遇到在聚合根被触摸之前无法检测到的并发冲突。

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

不能在实体之外进行的验证是您的业务逻辑验证。此验证取决于运行它的上下文(请参阅 Udi Dahan 的 Clarified CQRS)。

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

另外,我认为 UI 中发生的验证不应该在命令处理程序中重新检查,而应该在域中重新检查。该验证用于防止域损坏——如果不在域外执行,则域仍受无效参数的影响。

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

最后,您需要冒泡处理程序中拒绝的命令。我尽可能在例外情况下做到这一点。

于 2011-03-23T05:40:15.023 回答