首页 文章

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

提问于
浏览
32

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

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

  • 在命令处理程序中创建两个命令验证程序的实例 .

  • 第一个验证与客户端验证相同的命令数据(必填字段,有效电子邮件等)

  • 第二个验证器根据第二个验证器中的逻辑验证数据 . 像"is this customer active"之类的东西,或者其他什么东西 . 我知道不断变化的电子邮件不适合这里,但并不重要 . 重要的是这里有业务验证 .

  • 我们查看Validator.Validate(ICommand cmd)返回的ValidationResult,我们发现有错误

  • 我们不会从存储库中获取客户来调用AR上的UpdateEmail方法 . 那么我们在这一点上做什么呢?

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

感谢您的指导 .

谢谢

1 回答

  • 41

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

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

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

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

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

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

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

    最后,您需要冒泡从处理程序中拒绝的命令 . 我尽可能地用例外来完成这个 .

相关问题