对于命令是否应该具有返回值,似乎存在着无穷无尽的困惑。我想知道这种混淆是否仅仅是因为与会者没有说明他们的背景或情况。
这里有一些混乱的例子。
Udi Dahan 说命令“不会向客户端返回错误”,但是 在同一篇文章里给出了一个图表,其中命令确实向客户端返回错误。
Microsoft Press Store 的一篇文章称“命令... ... 不会返回响应”,但接下来给出了一个模棱两可的警告:
随着 CQRS 周围战场经验的增长,一些实践得到巩固并趋于成为最佳实践。在一定程度上与我们刚才所说的相反... ... 现在普遍认为,命令处理程序和应用程序都需要知道事务操作是如何进行的。必须知道结果。
那么,命令处理程序是否返回值?
从吉米 · 博加德(Jimmy Bogard)的“ CQRS 神话”中得到的启示,我认为这个问题的答案取决于你所说的程序性/上下文“象限”:
+-------------+-------------------------+-----------------+
| | Real-time, Synchronous | Queued, Async |
+-------------+-------------------------+-----------------+
| Acceptance | Exception/return-value* | <see below> |
| Fulfillment | return-value | n/a |
+-------------+-------------------------+-----------------+
命令“验收”主要指的是验证。假定验证结果必须同步地提供给调用方,无论命令“履行”是同步的还是排队的。
但是,似乎许多实践者并不从命令处理程序内部启动验证。在我看来,这要么是因为(1)他们已经找到了一种奇妙的方式来处理应用层的验证(例如,ASP.NET MVC 控制器通过数据注释检查有效状态) ,要么是(2)一种体系结构已经到位,假设命令被提交到(进程外)总线或队列。这些后面的异步形式通常不提供同步验证语义或接口。
简而言之,许多设计人员可能希望命令处理程序将验证结果作为(同步)返回值提供,但是他们必须接受所使用的异步工具的限制。
关于命令的“执行”,发出该命令的客户机可能需要知道新创建的记录或可能的故障信息(如“帐户透支”)的 scope _ Identity
在实时设置中,返回值似乎是最有意义的; 不应该使用异常来传达与业务相关的失败结果。但是,在“排队”上下文中... ... 返回值自然是没有意义的。
这也许可以概括所有的困惑:
很多(大多数?)CQRS 实践者假设他们现在或将来会合并一个异步框架或平台(总线或队列) ,从而声明命令处理程序没有返回值。但是,有些实践者并不打算使用这种事件驱动的构造,因此他们会认可(同步地)返回值的命令处理程序。
因此,例如,我认为当 Jimmy Bogard 提供了这个示例命令接口:
public interface ICommand<out TResult> { }
public interface ICommandHandler<in TCommand, out TResult>
where TCommand : ICommand<TResult>
{
TResult Handle(TCommand command);
}
毕竟,他的 Mediator 产品是一种内存工具。有鉴于此,我认为 Jimmy 小心翼翼地花时间从命令中产生一个空白的回复的原因不是因为“命令处理程序不应该有返回值”,而是因为他只是希望 Mediator 类具有一致的接口:
public interface IMediator
{
TResponse Request<TResponse>(IQuery<TResponse> query);
TResult Send<TResult>(ICommand<TResult> query); //This is the signature in question.
}
即使并非所有命令都有有意义的值可以返回。
我是否正确地捕捉到了为什么在这个主题上会有困惑? 我是否遗漏了什么?
在给出的答案的帮助下,我想我已经解开了困惑。简单地说,如果 CQRS 命令能够返回指示 完成状态的成功/失败,那么返回值是有意义的。这包括返回新的 DB 行标识,或任何不读取或返回域模型(业务)内容的结果。
我认为“ CQRS 命令”混淆的地方在于“异步”的定义和作用。“基于任务的”异步 IO 和异步体系结构(例如基于队列的中间件)之间有很大的区别。在前者中,异步“任务”可以并且将为异步命令提供完成结果。但是,发送到 RabbitMQ 的命令不会同样地收到请求/响应完成通知。正是后一种异步体系结构的上下文导致一些人说“没有异步命令这种东西”或“命令不返回值”