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

发布于 2024-10-26 05:38:18 字数 741 浏览 6 评论 0原文

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

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

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

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

感谢您的指导。

谢谢

I am new to CQRS and I am tying to make sense of business rule validation within the write side (domain). I know that client side validation should be done in terms of valid date (required field, string length, valid email, etc) and business rule/business domain related validation should be done in domain side. Actually, same client side validation rules should also be applied to command in the domain since we don't trust the users.

So, we have a valid command (AddEmailToCustomer) and the command handler is invoked on the command. Here is my approach to validation.

  1. Create instances of two command validators in the command handler.
  2. First one validates the command data same as client side validation (required field, valid email, etc.)
  3. Second validator validates the data based on logic within the second validator. Something like "is this customer active", or what ever. I know the changing email doesn't fit here but it is not important. Important thing is there is a business validation here.
  4. We look at the ValidationResult returned by the Validator.Validate(ICommand cmd) and we find out there are errors
  5. We will not get a customer from repository to call on the UpdateEmail method on the AR. So what do we do at this point?

Do I throw and exception in the command handler and add these errors there?
Do I send the command to error queue or somewhere else?
Do I respond with something like Bus.Reply and return error code? If so, what do I do with the error messages?
How do I communicate these errors to the user? I know I can email them later but in a web scenario I can send a request id in the command (or use the message id), and poll for response with the request id and display the error messages to user.

Your guidance is appreciated.

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

地狱即天堂 2024-11-02 05:38:18

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

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

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

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

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

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

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

最后,您需要冒泡处理程序中拒绝的命令。我尽可能地在例外情况下完成此任务。

It's important to know that commands can be rejected after they are sent to the handler.

At the very least, you could encounter a concurrency violation that cannot be detected until the aggregate root is touched.

But also, the validation that can occur outside of the entity is simple validation. Not only string lengths, numeric ranges, regex matching, etc. but also validation that can be reasonably satisfied through a query or view, like uniqueness in a collection. It's important to remember that validation involving a materialized view is likely to be eventually consistent, which is another reason a command could be rejected from the aggregate, inside the command handler. That said, to preempt the situation, I often use read models to drive UI choices which only allow valid actions.

Validation that cannot occur outside an entity is your business logic validation. This validation is dependent upon the context in which it is run (see Udi Dahan's Clarified CQRS).

Business logic should not be in a separate validation service. It should be in your domain.

Also, I'm of the opinion that validation which occurs in the UI should be re-checked not in the command handler, but in the domain too. That validation is there to prevent corruption to the domain -- if it is not performed outside the domain then the domain is still subject to invalid parameters.

Using command handlers to duplicate this validation is only a convention. If no other front end is sending commands, then it is a useless duplicate. If there are multiple front ends, it is just one choice of where to place the then-necessary duplicate validation, and in those cases I prefer to handle it in the domain.

Lastly, you will need to bubble up commands rejected from within the handler. I accomplish this with exceptions as much as possible.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文