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

she*_*per 32 validation command nservicebus business-rules cqrs

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

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

  1. 在命令处理程序中创建两个命令验证程序的实例.
  2. 第一个验证命令数据与客户端验证相同(必填字段,有效电子邮件等)
  3. 第二验证器基于第二验证器内的逻辑验证数据.像"这个客户是活跃的",或者说是什么.我知道不断变化的电子邮件不适合这里,但并不重要.重要的是这里有业务验证.
  4. 我们看一下Validator.Validate(ICommand cmd)返回的ValidationResult,我们发现有错误
  5. 我们不会从存储库中获取客户来调用AR上的UpdateEmail方法.那么我们在这一点上做什么呢?

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

感谢您的指导.

谢谢

que*_*rin 42

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

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

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

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

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

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

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

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

  • 如何将拒绝命令的错误传达给用户?电子邮件,带有请求ID的回调等? (5认同)
  • 关于qes所说的+1.我唯一不同意的是将验证逻辑放在域内,即使你有多个前端.在一天结束时,命令处理程序也是域的一部分(或者至少是唯一的网关).但是不要相信我的话:http://tinyurl.com/66kaorv (2认同)
  • 万一有人发现这个有用,我在CQRS系统中对命令验证有了更深入的了解.您可以在此处找到它:[如何验证CQRS应用程序中的命令](http://danielwhittaker.me/2016/04/20/how-to-validate-commands-in-a-cqrs-application/) (2认同)