NServicebus / CQRS:如何处理用户界面中的事情?
我一直在阅读 Udi Dahan 关于 [命令查询分离和 SOA][1] 的文本。考虑如何在我当前正在开发的系统中实际使用它,提出了一些问题...
1.
考虑以下情况,我有一个 WPF 客户端应用程序,允许用户编辑条目列表:
客户端应用程序启动。启动时,它订阅将处理和发布条目更改的命令服务,并查询 WCF 服务以获取完整的条目列表。收到条目列表后,在客户端队列忙于等待 WCF 答复时可能已发布到客户端队列的任何更改(由其他客户端)都将合并到列表中。
现在对我来说,似乎有一个(可能非常小的)机会,即客户端在负责更改的命令被处理之后订阅,并且 WCS 服务的查询在相同的更改提交到数据库之前启动。在这种情况下,我最终会在客户端中得到不正确的数据,这些数据不会(也永远不会)与数据库同步(除非重新启动客户端应用程序)。 这个问题是否真的存在,如果存在,应该如何处理?
2. 我的第二个问题是关于如何设计/实现用户界面:
用户现在想要更改列表中的条目;弹出一个窗口,数据发生更改,然后按下“确定”按钮:我们向命令处理程序发送一条消息来处理此更改。 用户期望看到确认(列表中的条目发生更改)或错误 信息。
现在我可以尝试以“同步”方式处理用户界面中的事情(让用户一次做一件事,并让他等待成功或失败,然后才允许他做其他事情),方法如下
- :用户按“确定”,禁用所有控件,因此无法进行进一步编辑。
- 创建一个带有超时等待...的 Saga?回复消息?命令服务发布的通知?两个都?
- 当收到响应消息时,列表中的数据会发生更改,控件会启用,我们就完成了 - 或者:
- 发生超时。命令消息已排队,因此更改最终会被执行,那么该怎么办呢?向用户显示一条消息(“这比预期花费的时间更长......”),在从命令服务收到通知后启用所有控件并更改客户端中的数据?但如果返回错误怎么办?用户可能已经开始做其他事情(可能正在编辑另一个条目),并且从之前的编辑尝试中弹出错误消息似乎不是一个好主意。
另一种方法可能是只发送命令并让用户继续下一步喜欢做的事情。也许会在用户界面某处的列表中显示所有未完成的命令,并带有成功或失败的指示符,以及用户在失败时显示错误消息的可能性。考虑到超时是例外情况,并且通常应在几秒钟内收到响应,这意味着该列表中通常最多应有 1 个未完成的命令。事实上,我不记得我曾经见过用户界面以这种方式做事意味着这可能不是一个好主意。
你的问题是? ;)
好吧,我只是想知道其他人是如何在他们的用户界面中解决这个问题的。可能有比我想出的两种可能不太聪明的方法更好的方法来处理 UI 中的事情?
对于冗长的文字表示歉意,并提前感谢您的回复。
[1]: http://www.udidahan .com/2008/08/11/command-query-separation-and-soa/《命令查询分离与SOA》
I've been reading Udi Dahan's text on [Command Query separation and SOA][1]. Thinking about how I would use this in practice in a system I'm currently working on raised some questions...
1.
Consider the following situation where I have a WPF client application that allows the user to edit a list of entries:
The client application is started. At startup, it subscribes to the command service that will handle and publish changes to the entries and it queries a WCF service for the complete list of entries. After receiving the list of entries, any changes (by other clients) that may have been published to the clients queue while it was busy waiting for a reply from WCF are merged into the list.
Now to me there seems to be a (probably very small) chance that the client subscribes just after a command responsible for a change was handled and that the WCS service's query is started just before the same change has been committed to the database. In this situation I'll end up with incorrect data in my client that is not (and will never get into) sync with the database (unless the client application is restarted). Does this problem really exist and if it does, how should it be handled?
2.
My second question is about how to design/implement the user interface:
The user now wants to change an entry in the list; a windows pops up, data is changed and the ok button is pressed: we send a message to our command handler to handle this change.
The user expects to see either a confirmation (the entry in the list changes) or an error
message.
Now I can try to handle things in the user interface in a 'synchronous' way (let the user do one thing at a time, and let him wait for success or failure before he's allowed to do anything else) the following way:
- After the user presses ok, disable all controls so no further editing is possible.
- Create a Saga with a timeout that waits for ...? The response message? The published notification from the command service? Both?
- When a response message is received the data in the list is changed, controls are enabled and we're done -- or:
- A timeout occurs. The command message has been queued, so the change will eventually be performed, so what to do? Show a message to the user ("this is taking longer than expected..."), enable all controls and change the data in the client once the notification is received from the command service? But what if an error is returned? The user may have started doing something else (maybe editing another entry) and popping up an error message from a previous edit attempt doesn't seem like a good idea.
Another approach would probably be to just send the command and let the user continue with whatever he likes to do next. Maybe show all outstanding commands in a list in the user interface somewhere, with an indicator of success or failure and the possibility for the user to display the error message in case of a failure. Given that timeouts are hopefully exceptional and that responses should normally be received within a few seconds would mean that this list should normally have at most 1 outstanding command in it.. That and the fact that I can't remember that I've ever seen a user interface doing things this way means that it's probably not a good idea.
And your question is ? ;)
Well, I'm just wondering about how other people are solving this in their user interfaces. Likely there are better ways of handling things in the UI than the two maybe not-so-clever ways that I came up with?
Apologies for the long text and thanks in advance for your replies.
[1]: http://www.udidahan.com/2008/08/11/command-query-separation-and-soa/"Command Query separation and SOA"
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
对于问题 1,查询的标准解决方案是创建客户端 RPC 请求/响应所针对的服务器端持久查询存储。
对于问题 2,答案很大程度上取决于领域 - 命令的种类、用户间协作的性质。作为首要规则,请考虑更改 UI 和/或命令的数据/处理的方法,以便命令几乎不会失败(除非我们谈论的是恶意用户)。
希望有帮助。
To question number 1, the standard solution for querying is to create a server-side persistent query store that the client RPC-request/responses against.
To question number 2, the answer is very much dependent on the domain - the kinds of commands, the nature of inter-user collaboration. As an overarching rule, think of ways you can change the UI and/or the data/handling of the commands such that commands will hardly ever fail (unless we're talking about malicious users).
Hope that helps.