我正在努力解决这个架构问题, 我们的系统使用NService Bus,并使用NEventStore和NES实现带有EventSourcing的DDD。 客户端应用程序是WPF
我仍然无法确定更新用户界面的最佳做法, 例如: 我有一个UI来创建(Batch {Id,StartDate,EndDate等...}),在用户点击保存后,我发送命令(CreateBatch),
Bus.Send<CreateBatch> (batch => {batch.Id = Guid.NewGuid(); .... etc });
现在,
选项#1
我可以按如下方式注册回复:
private void btnSave_Click(object sender,EventsArg e){
Bus.Send<CreateBatch> (batch => {batch.Id = Guid.NewGuid(); .... etc })
.Register<int>(c=> {
MessageBox.Show("Command Succeded");
Close();});
}
并在服务器端:
public void Hanlde(CreateBatch cmd){
//initiate aggregate and save it.
Bus.Return( /*What ?? Success Code?*/);
}
在这种情况下,如何处理错误? (验证错误,例如已经在同一天开始批量启动了吗?),因为你只能返回int或string !!
选项#2:
发送命令,关闭窗口,假设记录已添加到主网格中,直到用户刷新网格并从ReadModel数据库中获取真实数据,或者发现记录未添加但没有任何关于什么的信息发生了!!
private void btnSave_Click(object sender,EventsArg e){
Bus.Send<CreateBatch> (batch => {batch.Id = Guid.NewGuid(); .... etc });
Close();
}
选项#3
发送命令,关闭窗口,假设记录已添加到主网格中,但将其标记为(进行中),等待(BatchCreated)事件到达,检查它是否与我们之前发送的批次ID相同,然后将记录标记为持续存在于网格中。
private void btnSave_Click(object sender,EventsArg e){
Bus.Send<CreateBatch> (batch => {batch.Id = Guid.NewGuid(); .... etc });
Close();
}
public class BatchHandler : IHandleMessages<BatchCreated>
{
public void Handle(BatchCreated evnt)
{
if(SomeCachForSentIDS.Contains(evnt.BatchId)
///Code to refresh the row in the grid and reflect that the command succeeded.
}
}
如果您有更好的选择,或对上述选项有任何建议,甚至有关如何处理此类情况的一些链接,我将不胜感激。
谢谢。
答案 0 :(得分:5)
将消息传递到这样的解决方案中的一个重要原则是确保命令几乎不会失败(正如@Gope在评论中提到的那样)。
这意味着在发送消息之前,应该在客户端执行各种验证检查。
现在,即使在进行客户端验证时,您仍然可能会遇到竞争条件 - 2个用户在创建批处理的同时以某种方式相互冲突。处理此问题的方法是查明用户意图,可能更改任务的性质以及UI,以使新命令即使在并行处理的情况下也能成功。
就像对解决方案的简单抨击一样,您可以重新定义逻辑以为批处理引入新状态 - 如“冲突”,如果另一批处理同时启动,则将设置该状态。这样命令成功(创建批处理),然后你使用SignalR这样的东西将这种状态的通知推回给用户,这样他们就可以去纠正它。
最后,您可能希望完全重新考虑使用消息传递,只需转到简单的2层同步解决方案。每种方法都有时间和地点。
答案 1 :(得分:1)
如何为异步消息传递设计这些用户界面(特别是在我们被灌输到CRUD思维模式之后)是每个系统中的百万美元问题。
我同意Udi的评估100%。此外,您的问题似乎对确切的业务需求非常不透明,但CreateBatch命令和BatchCreated事件名称的CRUD性质让我想知道它是否真的对消息传递有用。
如果您发现自己处于必须等待CreateBatch完成的情况,那么您可以做更多的事情,也许您根本不应该有CreateBatch。也许你应该只是创建一些“本地”(这可能意味着JavaScript中的客户端,或者Udi建议,在最简单的2层数据库模型中),然后发送命令来完成实际工作(也许是ProcessBatch?)一切都完成了。
毕竟,消息传递的目标不是完全将Web层与数据库的请求分开。