C# 我的传奇结构是正确的解决方案吗?(N服务总线)
我直接切入。我正试图通过发送到我们银行的文件来实现信用卡支付的自动化。银行不会实时验证卡付款。银行隔夜处理付款,并在第二天发送一份包含成功和失败付款的响应文件 我有一个web应用程序,当它接受或取消付款时,一条包含付款/取消详细信息的消息(通过Bus.Send)发送到命令消息处理器 然后,处理器发布(通过Bus.Publish)此消息,以供所有服务查看 一项服务需要执行以下操作:C# 我的传奇结构是正确的解决方案吗?(N服务总线),c#,nhibernate,nservicebus,saga,C#,Nhibernate,Nservicebus,Saga,我直接切入。我正试图通过发送到我们银行的文件来实现信用卡支付的自动化。银行不会实时验证卡付款。银行隔夜处理付款,并在第二天发送一份包含成功和失败付款的响应文件 我有一个web应用程序,当它接受或取消付款时,一条包含付款/取消详细信息的消息(通过Bus.Send)发送到命令消息处理器 然后,处理器发布(通过Bus.Publish)此消息,以供所有服务查看 一项服务需要执行以下操作: 从收到第一条消息开始一段传奇故事 发出超时请求以关闭业务 跟踪所有后续消息(在saga中) 收到超时后,将付款和取
- 从收到第一条消息开始一段传奇故事
- 发出超时请求以关闭业务
- 跟踪所有后续消息(在saga中)
- 收到超时后,将付款和取消消息转换为银行文件李>
public class PaymentRequestCancelledSagaBase : IContainSagaData
{
// the following properties are mandatory
public virtual Guid Id { get; set; }
public virtual string Originator { get; set; }
public virtual string OriginalMessageId { get; set; }
// List of all the received PaymentRequestedMessages
public virtual List<PaymentRequested> PaymentRequestedMessages;
// List of all the received PaymentCancelledMessages
public virtual List<PaymentCancelled> PaymentCancelledMessages;
}
公共类PaymentRequestCancelledSagaBase:IContainSagaData
{
//以下属性是必需的
公共虚拟Guid Id{get;set;}
公共虚拟字符串发起者{get;set;}
公共虚拟字符串OriginalMessageId{get;set;}
//收到的所有PaymentRequestedMessages的列表
公共虚拟列表PaymentRequestedMessages;
//收到的所有PaymentCanceledMessages的列表
公共虚拟列表付费取消消息;
}
有什么想法吗?我不确定我的想法是否与Udi等人一致,但我一直认为saga数据是关于消息的非常轻量级的元数据,它不应该包含太多实际的消息数据 您可以对每个付款请求和相应的批准/取消有一个传奇故事,但假设银行要求您在每个工作日将它们全部批处理在一起,或者对每个文件收取固定金额,这是常见的 在这种情况下,在消息传递系统(NServiceBus)的底层,您可能会或应该有某种事务系统,它实际上跟踪事务本身。如果他们被分组到某一类型的批次(即工作日),那么批次必须有一个ID。除了关于整个流程状态的基本信息(即,您收到银行的回复了吗?)之外,这就是传奇应该引用的ID 服务总线本身并不是一个系统,它是独立系统和组件相互通信的一种方式。事实上,传说一旦完成(通过
MarkAsComplete
)就会被删除,因此它们实际上不是存储“永久”信息的地方
在我的世界里,传奇的数据应该是这样的:
public class PaymentProcessingSagaData : IContainSagaData
{
public virtual Guid Id { get; set; }
public virtual string Originator { get; set; }
public virtual string OriginalMessageId { get; set; }
public virtual int RequestBatchId { get; set; }
public virtual DateTime? WhenRequestBatchClosed { get; set; }
public virtual string BankRequestFileName { get; set; }
public virtual DateTime? WhenRequestFileSent { get; set; }
public virtual string BankResponseFileName { get; set; }
public virtual DateTime? WhenResponseFileReceived { get; set; }
public virtual int PaymentBatchId { get; set; }
}
对应于以下操作顺序:
PaymentRequested
事件RequestBatchId
,该ID将成为saga关联ID。然后设置业务关闭的超时时间WhenRequestBatchClosed
,并发布PaymentRequestBatchClosed
事件PaymentRequestBatchClosed
事件,创建付款文件(设置BankRequestFileName
),发布一个RequestFileAvailable
事件,表示文件已准备就绪RequestFileAvailable
事件并启动上载过程,该过程(例如)将文件FTPs到银行服务器,在请求文件发送时更新,并发布RequestFileSent
事件
BankResponseFileName
和,并发布ResponseFileAvailable
事件
ResponseFileAvailable
事件,处理文件,创建付款批次,更新PaymentBatchId
,并可选择发布最终的PaymentsProcessed
事件并完成saga,您可以很容易地使用布尔标志指示哪些步骤已完成。但重要的是,您的传奇是跟踪事务状态,而不是事务数据。
不要错误地试图把一切都塞进一个传奇故事。它并不是要取代事务系统,它只是一点胶水,可以将所有系统粘合在一起。IList受支持,请参见制造示例。我会将支付ID列表保存在该列表中,以便银行文件处理程序使用这些支付ID查找交易金额,而不是在消息中传输这些信息?在这种情况下,我需要向processor添加一个数据访问层,以获取消息中没有的数据。您也可以存储该信息,就像生产示例中使用的订单行(DTO)一样。web应用程序不知道可能添加了多少付款,也不知道可能没有添加多少付款,因此不会生成批处理。在收到超时消息并整理消息之前,不会生成批处理。处理器生成的唯一标识符实际上是批次ID。这包括在银行文件和发送文件后发送的BankFileSent消息中。另一个处理器使用BankFileSent并更新付款记录。当响应返回时,我们有唯一标识符和最终更新的付款ID。@Fellmeister:我很抱歉