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

时间:2011-03-22 22:33:10

标签: validation command nservicebus cqrs business-rules

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

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

  1. 在命令处理程序中创建两个命令验证程序的实例。
  2. 第一个验证与客户端验证相同的命令数据(必填字段,有效电子邮件等)
  3. 第二个验证器根据第二个验证器中的逻辑验证数据。像“这个客户是活跃的”,或者说是什么。我知道不断变化的电子邮件不适合这里,但并不重要。重要的是这里有业务验证。
  4. 我们查看Validator.Validate(ICommand cmd)返回的ValidationResult,我们发现有错误
  5. 我们不会从存储库中获取客户来调用AR上的UpdateEmail方法。那么我们现在该做什么呢?
  6. 我是否在命令处理程序中抛出异常并在那里添加这些错误? 我是否将命令发送到错误队列或其他地方? 我是否回复Bus.Reply之类的内容并返回错误代码?如果是这样,我该如何处理错误消息? 如何将这些错误传达给用户?我知道我可以稍后给他们发电子邮件,但在网络场景中,我可以在命令中发送请求ID(或使用消息ID),并使用请求ID轮询响应,并向用户显示错误消息。

    感谢您的指导。

    由于

1 个答案:

答案 0 :(得分:42)

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

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

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

验证不能在实体外发生是您的业务逻辑验证。此验证取决于运行它的上下文(see Udi Dahan's Clarified CQRS)。

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

另外,我认为在UI中发生的验证不应该在命令处理程序中重新检查,而是在域中重新检查。该验证是为了防止域的损坏 - 如果它不在域外执行,那么域仍然受到无效参数的限制。

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

最后,您需要冒泡从处理程序中拒绝的命令。我尽可能地做到了这一点。