在CQRS中注册EventHandler

我正在尝试使用CQRS和DDD模拟购买域,我知道我在域中引发事件但我不知道在我使用命令时在哪里注册它们。 应该在命令处理程序中注册事件处理程序吗? 或者我误解了一些东西。 这是我的过程,你可以帮助建模吗?

最终确定采购订单命令,比命令处理程序最终确定订单(从存储库获取订单,更改其状态并保存回db),订单最终事件发生在域模型中,而不是事件处理程序使用id及其行项找到此订单,查找它供应商联系信息(可能是电子邮件甚至是外部服务)并通知他新的采购订单。

我的命令和命令处理程序在应用程序层中(事件处理程序也应该在这里?)。 域层中的域模型,事件和IRepositories。 基础架构层中的存储库实现。

域模型(跳过大多数属性):

public class PurchaseOrder { public PurchaseOrder(int purchaseOrderID, int supplierID, bool isOrderFinalized) { PurchaseOrderID = purchaseOrderID; SupplierID = supplierID; IsOrderFinalized = isOrderFinalized; } public int PurchaseOrderID { get; private set; } public int SupplierID { get; private set; } public bool IsOrderFinalized { get; private set; } public static PurchaseOrder CreateNew(int supplierID) { return new PurchaseOrder(0, supplierID, false); } public void FinalizeOrder() { IsOrderFinalized = true; DomainEvents.Raise(new PurchaseOrderFinalized(PurchaseOrderID)); } } 

FinalizePurchaseOrder命令

 public class FinalizePurchaseOrder : ICommand { public FinalizePurchaseOrder (int purchaseOrderID) { PurchaseOrderID = purchaseOrderID; } public int PurchaseOrderID { get; private set; } } 

命令处理程序

 public class PurchaseOrdersCommandHandler : ICommandHandler { public void Handle(FinalizePurchaseOrder command) { var purchaseOrder = purchaseOrderRepository.FindByID(command.PurchaseOrderID); // Should i register event handler here? // DomainEvents.Register(PurchaseOrderFinalizedHandler); purchaseOrder.FinalizePurchaseOrder(); purchaseOrderRepository.Save(purchaseOrder); } } 

事件和事件处理程序如下所示:

 public class PurchaseOrderFinalized { public PurchaseOrderFinalized(int purchaserOrderID) { PurchaseOrderID = purchaseOrderID; } } public void PurchaseOrderFinalizedHandler (PurchaseOrderFinalized evt) { // TODO: Get PurchaseOrder with its line items, and notify supplier about new order } 

应该在命令处理程序中注册事件处理程序吗?

除非它们是动态的,否则不是。 您通常会在应用程序的CompositionRoot中将它们连接起来。 我们的想法是,当您的应用加载时以及“准备好”之前,所有接线都会发生。

你在哪里注册你的命令处理程序? 您应该在同一个地方注册您的事件处理程序。

[UPDATE]

有关示例,请参阅https://github.com/gregoryyoung/mr/blob/master/CQRSGui/Global.asax.cs

您应该查看Udi Dahan关于Reliable Messaging的演讲。

典型的体系结构通常包括一些消息队列/事件总线。 您的事件处理程序在启动时使用总线注册其对事件的订阅。 正如@tomliversidge指出的那样,通常会在组合根目录中。

将更改保存到聚合时,还会保存该命令引发的DomainEvent。 这两个写入都发生在同一个事务中,在同一个记录簿中。 所以他们都成功了,或者他们都失败了。

如果交易失败,那么数据模型没有改变,没有人需要得到任何通知 – 像往常一样向客户报告失败并继续你的生活。

如果命令成功,那么我们需要安排要发布的事件。 这是一种基本的异步操作 – 事件处理程序对记录簿的任何其他写入都将在它们自己的事务中。

自然要做的是让命令处理程序安排任务将事件发布到总线。 调度完任务后,命令处理程序返回(任务运行时并不关心)。

但由于事件发生在记录簿中,您可以随时再次发布它们。