C# 如何获得CQR变更的即时反馈
让我们假设我有下一个伪代码来在我的WebApi项目中实现基于命令的CQR变更(实际上,事件来源也是有问题的):C# 如何获得CQR变更的即时反馈,c#,asp.net,architecture,cqrs,event-sourcing,C#,Asp.net,Architecture,Cqrs,Event Sourcing,让我们假设我有下一个伪代码来在我的WebApi项目中实现基于命令的CQR变更(实际上,事件来源也是有问题的): public IHttpActionResult ChangeVendor(ChangeVendorModel changeModel) { /* 1 */ // user input validation /* 2 */ var changeCommand = changeModel.MapTo<ChangeVendorCommand>();
public IHttpActionResult ChangeVendor(ChangeVendorModel changeModel)
{
/* 1 */ // user input validation
/* 2 */ var changeCommand = changeModel.MapTo<ChangeVendorCommand>();
/* 3 */ bus.Send(changeCommand); // start the change processing
/* 4 */ return Ok();
}
public IHttpActionResult ChangeVendor(ChangeVendor模型changeModel)
{
/*1*///用户输入验证
/*2*/var changecondm=changeModel.MapTo();
/*3*/bus.Send(changeCommand);//开始更改处理
/*4*/返回Ok();
}
解释:
b。假设发生了记录版本冲突(数据冲突)或模型未通过业务规则(域冲突)。我如何能在公交车上立即通知用户这一点?在一个设计糟糕的系统中,用户可以看到一个成功的结果,因为我们成功地在总线上安排了更改,之后,当尝试应用实际更改时,他们可以看到带有错误的通知。正如我在评论中所建议的,您可以等待发出完成信号的事件,并且只有在收到该事件时才返回给用户。一些伪代码:
public IHttpActionResult ChangeVendor(ChangeVendorModel changeModel)
{
var changeCommand = changeModel.MapTo<ChangeVendorCommand>();
bus.Send(changeCommand); // start the change processing
var replyReceived=false;
bool success = false;
while(!replyreceived)
{
Task vendorChanged = Task.Factory.StartNew(()=>
{
var reply=bus.Receive<VendorChanged>());
if(reply.CorrelationToken==changeCommand.CorrelationToken)
{
replyReceived=true;
success=true;
}
},SomeTimeout);
Task vendorChangedFailed = Task.Factory.StartNew(()=>
{
var reply=bus.Receive<VendorChangeFailed>());
if(reply.CorrelationToken==changeCommand.CorrelationToken)
{
replyReceived=true;
success=false;
}
},SomeTimeout());
Task.WaitAny(new Task[]{vendorChanged,vendorChangeFailed});
}
if(success)
{
return Ok();
}
else
{
return ChangeVendorFailed();
}
}
public IHttpActionResult ChangeVendor(ChangeVendor模型changeModel)
{
var changecondm=changeModel.MapTo();
bus.Send(changeCommand);//开始更改处理
var replyReceived=假;
布尔成功=假;
而(!replyreceived)
{
Task vendorChanged=Task.Factory.StartNew(()=>
{
var reply=bus.Receive());
if(reply.CorrelationToken==changeCommand.CorrelationToken)
{
replyReceived=真;
成功=真实;
}
},超时);
Task vendorChangedFailed=Task.Factory.StartNew(()=>
{
var reply=bus.Receive());
if(reply.CorrelationToken==changeCommand.CorrelationToken)
{
replyReceived=真;
成功=错误;
}
},SomeTimeout());
WaitAny(新任务[]{vendorChanged,vendorchangefiled});
}
如果(成功)
{
返回Ok();
}
其他的
{
返回ChangeVendorFailed();
}
}
显然,receive需要使用自己的订阅,以确保它不接受其他实例的回复,并且您可以创建订阅以仅接收具有正确关联令牌或其他标识属性的消息,但这给了你一个办法,让你的异步工作流程在用户看来是同步的。你可以先不返回
200-OK
,而是返回一些更接近你实际操作的东西,比如202-ACCEPTED
。然后消费者将知道他们需要在将来的某个时候检查调用的结果(您可能会发送一个位置头或类似的消息,让客户端知道在哪里查找结果)这是一个很好的建议,但听起来好像客户知道内部实现是工作型的,他们需要稍后再来检查结果。它适用于繁重的工作,但对于简单的记录更新来说,这是一种过分的做法。如果您不想向客户公开这一点,那么您必须在总线上创建一个指示成功或失败的事件订阅,并等待收到其中一个事件,然后可以返回200-OK
或相应的错误代码(或超时)。除非您这样做,否则不能假装您的内部实现与工作不一样。您还可以考虑返回<代码> 303,查看其他以允许客户端获得响应,并希望在客户端到达的时候大部分时间都将完成该处理。该订阅将以异步方式触发,并且所有的工作都将准确地描述我在一个设计不良的系统中的示例。使用303状态代码(以及302)会导致我们在变更应用程序和查询结果之间竞争。和往常一样,如果没有响应,请注意无限循环。github上有一篇文章介绍了一种使用类似于上述令牌的解决方案。