【问题标题】:What triggers UI refresh in CQRS client app?什么触发 CQRS 客户端应用程序中的 UI 刷新?
【发布时间】:2012-07-05 03:46:27
【问题描述】:

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

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

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

其他信息

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

跟进问题

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

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

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

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

【问题讨论】:

    标签: cqrs


    【解决方案1】:

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

    1. 该命令是一种真正的“一劳永逸”方法,它通知后端状态更改,但此更改不需要反映在 UI 中,或者更改对 UI 根本不重要.

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

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

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

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

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

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

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

    【讨论】:

    • 很好的总结,听起来你很接近我在最初发帖后的想法。我选择不使用领域事件来传达通过/失败,并利用任务并行库 (TPL) 来满足我的需求,同时保持异步性。就我而言,当我向命令总线发送消息时,我会得到一个任务作为回报。这允许我在异步操作完成时接收通知,并支持将异常传递回调用代码。现在我可以简单地在任务的延续中刷新数据。
    • 我相信这与 CQRS 一致,因为命令和查询仍然是分开的,但可以让我更好地控制 UI,正如您所说,如果 UI 要运行,您必须取消分离它们根据需要/预期。
    • 另外,这非常适合 MVVM!
    【解决方案2】:

    我的两分钱。

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

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

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

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

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

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

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

    【讨论】:

    • 另外,处理偶尔连接的客户端,当它失去连接时应该从服务器传播给它的事件(如果它只是断开一段时间)。可能会有一定的时间阈值,需要客户端完全从 ReadModel 重新初始化。
    • 我也在努力解决这个问题。我完全同意浏览器向服务器发送命令(异步还是同步?我不确定哪种方法是正确的,但暂时不要这样做),服务器使用命令并进行一些状态更改,然后发布更改的事件一些指示变化的信息。我的问题是,我们如何设计这个更改的事件,它可以被浏览器 javascript 读取,它会修改 ui 和一些对此事件感兴趣的服务器端东西?
    • 这个更改的事件应该使用 JSON 发送到服务器。它应该只携带执行服务器需要的任何操作所需的数据。 IE。对象的新状态,对象的原始状态应该已经存在于服务器上。服务器应该能够通过使用某种 UUID 来匹配正在更改状态的对象。
    【解决方案3】:

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

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

    【讨论】:

    • 这可以解释为什么我看到的每个 CQRS 示例都使用 MVC 客户端。不幸的是,我正在使用 Silverlight(可能在不久的将来切换到 WPF)。这种方法在那里行不通。但是,下次我使用 ASP.NET MVC 时有很好的信息。
    • 我是否试图将方形钉 (CQRS) 强制插入圆孔 (Silverlight)?
    • 您在 Silverlight 应用程序中使用 MVVM 模式吗?
    • 这里是一个示例 SL 应用程序。也许您会通过查看该代码找到答案:thecqrskitchen.codeplex.com
    • 我正在使用 MVVM。该示例似乎让 ViewModel 处理了一个事件,然后重新发出查询以刷新数据。但是,似乎在命令实际执行之前引发了事件。这对时间做了一个相当大的假设,因为操作可能需要一些时间才能在服务器上完成,并且在调用甚至开始之前刷新数据似乎是检索未更改状态的可靠方法。既然操作最终会调用 Web 服务,那么在服务调用返回时引发事件不是更好吗?
    【解决方案4】:

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

    1) 设计您的用户界面,以便用户不会立即看到其更改。比如一条信息告诉他他的行动是成功的,并为他提供不同的选择来继续他的工作。这应该可以让您有足够的时间来更新您的 readmodel。

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

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

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

    【讨论】:

      猜你喜欢
      • 2011-06-16
      • 2020-03-29
      • 2016-02-14
      • 1970-01-01
      • 1970-01-01
      • 2020-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多