我正在尝试学习并将CQRS设计方法(模式和架构)应用于新项目,但似乎缺少一个关键部分。
我的客户端应用程序执行查询并从读取模型中检索轻量级只读DTO列表。用户选择一个项目并单击按钮以启动某个操作。通过创建相应的命令对象并将其发送到写入模型(命令处理程序执行操作,更新数据存储等等)来执行操作。但是,在某些时候,我需要更新UI以反映对该行动产生的申请状态。
用户界面如何知道何时需要刷新原始列表?
其他信息
我注意到大多数讨论CQRS的文章/博客都在他们的示例中使用了MVC客户端应用程序。我现在正在开发一个Silverlight客户端,并开始怀疑这种模式在这种情况下是不起作用。
跟进问题
在更多地考虑Bartlomiej的回应和随后的讨论之后,我想知道CQRS中的错误处理。鉴于命令基本上是即发即弃的异步操作,我们如何向UI报告错误情况?
我看到'刷新UI'采用以下两种形式之一:
即使在MVC中使用Post-Redirect-Get模式,在知道操作结果之前,您也无法真正重定向。到目前为止,我见过的所有例子都没有解决这些现实问题。
答案 0 :(得分:5)
我一直在努力解决WPF客户端的类似问题。任何数据的重新查询触发器取决于您更新的数据,命令往往属于类别:
该命令是一个真正的fire and forget方法,它通知后端状态更改,但此更改不需要反映在UI中,或者更改对UI不重要
该命令将改变单个查询的结果
该命令将改变多个查询的结果,通常(至少在我的域中)以级联方式改变,也就是说,更改单个“高级”数据的状态可能会影响许多“低级“缓存。
我的第一个触发器是页面加载,很少有项目可以免除,因为大多数页面必须假设数据自上次访问以来已经更新。虽然有些系统可能只能以这种方式更新财务和其他关键数据而逃脱。
对于简短命令,我还会在从命令返回“成功”时更新数据。虽然这主要是懒惰,因为恕我直言,所有CQRS命令都应该异步触发。如果你的实现期望命令和查询之间的延迟很高,那么它仍然是一个我不能没有的选择,但你可能不得不这样做。
我开始使用的一种模式是中介(大多数MVVM框架都带有一个)。当我触发命令时,我还向调解器发出一条消息,指明启动了哪个命令。每个缓存(视图模型属性Retriever<T>
)侦听影响它的命令,然后进行适当更新。我尝试最小化消息的数量,同时仍然最小化从单个消息更新不必要的高速缓存的数量,因此我(希望)最终得到更新原因的短名单,每个'原因'更新高速缓存列表。
另一种方法是简单的诚实,我发现通过图形化地揭示系统如何自我更新使用户更愿意对此感到耐心。在触发命令时会显示一些UI,表示您正在等待成功响应,如果出现错误,您可以提供重试/显示错误,成功时您将开始更新相关字段。请记住,这个命令可能是从另一个终端(你不知道的)发出的,所以数据最终需要超时,以避免其他机器调用的状态变化丢失。
具有讽刺意味的是,在客户端上更新缓存和值的唯一有效方法是再次分离命令和查询,无论是通过硬编码还是类似哈希映射。
答案 1 :(得分:2)
我的两分钱。
我认为MVVM实际上很适合CQRS。 ViewModel只是一个可观察的ReadModel。
1 - 通过对ReadModel的查询初始化ViewModel状态。
2 - ViewModel上的更改会自动反映在绑定到它的任何视图上。
3 - ViewModel上的某些更改会触发命令以推送到消息队列,负责将这些命令发送到服务器的对象将这些消息从队列中取出并将它们发送到WriteModel。
4 - 客户端应该格式良好,这意味着ViewModel应该在触发命令之前执行适当的验证。触发命令后,可以将任何事件通知发布到事件总线上,以便客户端将更改传达给对这些更改感兴趣的系统中的其他ViewModel或组件。这些事件应包含必要的相关信息。通常,这意味着其他视图模型通常不必因更改而重新查询读取模型,除非它们依赖于需要检索的其他数据。
5 - 有一个对象连接到服务器上的消息总线,以便在其他客户端进行此客户端有兴趣了解的更改时进行实时推送通知,并在必要时回退到长轮询。它将这些传播到内部消息总线,将客户端上的组件连接在一起。
6 - 要处理的最后一部分是客户端偶尔可以连接,这应该是命令失败的唯一原因(他们目前没有互联网访问权限),这是应该通知客户端的时间问题。
答案 2 :(得分:1)
在我的ASP.NET MVC 3中,我根据用例使用了2种技术:
答案 3 :(得分:0)
据我所知,你可以采取两种主要方式:
1)设计您的UI,以便用户不会立即看到其更改。比如告诉他他的行动是成功的消息,并为他提供不同的选择以继续他的工作。这应该给你足够的时间来更新你的readmodel。
2)更复杂,但您可以保留已发送到服务器的信息并在界面中显示它们。
我想最重要的是,如果可以,请教育您的用户,以便他们知道数据不在这里的原因......
我现在只考虑它,但这些是用于同步命令处理,而不是异步,异步事情在大脑上变得非常困难......客户端界面也变成了事件食者......