14

我正在尝试学习 CQRS 设计方法(模式和架构)并将其应用于新项目,但似乎缺少关键部分。

我的客户端应用程序执行查询并从读取模型中检索轻量级只读 DTO 列表。用户选择一个项目并单击一个按钮以启动一些操作。该操作是通过创建相应的命令对象并将其发送到写入模型(命令处理程序执行操作、更新数据存储等)来执行的。但是,在某些时候,我需要更新 UI 以反映对由操作产生的应用程序的状态。

UI 如何知道何时刷新原始列表?

附加信息

我注意到大多数讨论 CQRS 的文章/博客在他们的示例中都使用 MVC 客户端应用程序。我现在正在开发 Silverlight 客户端,我开始怀疑这种模式在这种情况下是否行不通。

后续问题

在更多地考虑了 Bartlomiej 的回应和随后的讨论之后,我想知道 CQRS 中的错误处理。鉴于命令基本上是即发即弃的异步操作,我们如何向 UI 报告错误情况?

我看到“刷新 UI”采取以下两种形式之一:

  1. 操作成功,数据已更改,应更新 UI 以反映这些更改
  2. 操作失败,数据未更改,但应通知用户失败和潜在的纠正措施。

即使在 MVC 中使用 Post-Redirect-Get 模式,在您知道操作的结果之前,您也无法真正进行重定向。到目前为止,我所看到的例子都没有解决这些现实世界的问题。

4

4 回答 4

4

我一直在为 WPF 客户端解决类似的问题。任何数据的重新查询触发器取决于您更新的数据,命令往往分为以下几类:

  1. 该命令是一种真正的即发即弃的方法,它通知后端状态更改,但这种更改不需要反映在 UI 中,或者更改对 UI 根本不重要。

  2. 该命令将更改单个查询的结果

  3. 该命令将更改多个查询的结果,通常(至少在我的域中)以级联方式更改,也就是说,更改单个“高级”数据的状态可能会影响许多“低级”缓存。

我的第一个触发器是页面加载,很少有项目可以免除这一点,因为大多数页面必须假定数据自上次访问以来已更新。尽管某些系统可能只需以这种方式更新财务和其他关键数据即可逃脱。

对于短命令,我还会在命令返回“成功”时更新数据。虽然这主要是懒惰,因为恕我直言,所有 CQRS 命令都应该异步触发。它仍然是我不能没有的一个选项,但如果您的实现期望命令和查询之间存在高延迟,您可能不得不这样做。

我开始使用的一种模式是中介(大多数 MVVM 框架都有一个)。当我发出命令时,我还会向中介者发出一条消息,指定启动了哪个命令。每个缓存(一个视图模型属性Retriever<T>)都会监听影响它的命令,然后适当地更新。我尝试最小化消息的数量,同时仍然最小化从单个消息中更新不必要的缓存的数量,所以我(希望)最终会得到一个更新原因的候选列表,每个“原因”都会更新一个缓存列表。

另一种方法是简单的诚实,我发现通过以图形方式展示系统如何更新本身使用户更愿意耐心等待。在触发命令时显示一些 UI,指示您正在等待成功响应,在错误时您可以提供重试/显示错误,在成功时您开始更新相关字段。请记住,此命令可能已从另一个终端(您不知道)触发,因此数据最终需要超时以避免丢失其他机器调用的状态更改。

注意到具有讽刺意味的是,在客户端上更新缓存和值的唯一有效方法是再次取消分离命令和查询,无论是通过硬编码还是哈希图之类的方式。

于 2012-08-28T11:47:25.370 回答
2

我的两分钱。

我认为 MVVM 实际上非常适合 CQRS。ViewModel 简单地变成了一个可观察的 ReadModel。

1 - 您通过对 ReadModel 的查询来初始化您的 ViewModel 状态。

2 - ViewModel 上的更改会自动反映在绑定到它的任何视图上。

3 - 您的 ViewModel 上的某些更改会触发一个传播到消息队列的命令,负责将这些命令发送到服务器的对象将这些消息从队列中取出并将它们发送到 WriteModel。

4 - 客户端应该是正确的,这意味着 ViewModel 在触发命令之前应该已经执行了适当的验证。一旦命令被触发,任何事件通知都可以发布到事件总线上,以便客户端将更改传达给系统中对这些更改感兴趣的其他 ViewModel 或组件。这些事件应携带必要的相关信息。通常,这意味着其他视图模型通常不必因为更改而重新查询读取模型,除非它们依赖于需要检索的其他数据。

5 - 有一个对象连接到服务器上的消息总线以在其他客户端进行此客户端有兴趣了解的更改时进行实时推送通知,必要时回退到长轮询。它将这些信息传播到将客户端上的组件联系在一起的内部消息总线。

6 - 最后要处理的部分是客户端可以偶尔连接的事实,这应该是命令失败的唯一原因(他们目前没有互联网访问权限),此时应该通知客户端出现问题。

于 2013-11-13T02:06:50.330 回答
1

在我的 ASP.NET MVC 3 中,我根据用例使用 2 种技术:

  • 众所周知的 Post-Redirect-Get 模式非常适合 CQRS。触发命令的 MVC 操作将重定向到执行查询的操作。
  • 在某些情况下,比如其他客户端的实时更新,我依赖于域事件/消息。我创建了一个事件处理程序,它使用 singlarR 将更改推送到所有已连接且感兴趣的客户端。
于 2012-07-05T07:44:19.377 回答
0

据我所知,您可以采取两种主要方法:

1)设计你的用户界面,让用户不会马上看到它的变化。比如一条信息告诉他他的行动是成功的,并为他提供不同的选择来继续他的工作。这应该为您赢得足够的时间来更新您的 readmodel。

2)更复杂,但您可能会保留已发送到服务器的信息并在界面中显示它们。

我想最重要的是,如果可以的话,教育你的用户,让他们知道为什么数据不在这里......但是!

我现在才考虑它,但这些是用于同步命令处理,而不是异步,在异步中事情变得更加困难......客户端界面也成为事件吞噬者......

于 2012-07-09T12:39:53.570 回答