在CQRS中注册EventHandler

时间:2016-07-20 13:15:18

标签: c# events event-handling domain-driven-design cqrs

我正在尝试使用CQRS& amp; 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<FinalizePurchaseOrder>
{
    public void Handle(FinalizePurchaseOrder command)
    {
        var purchaseOrder = purchaseOrderRepository.FindByID(command.PurchaseOrderID);
        // Should i register event handler here?
        // DomainEvents.Register<PurchaseOrderFinalized>(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
}

2 个答案:

答案 0 :(得分:3)

  

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

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

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

[UPDATE]

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

答案 1 :(得分:0)

您应该查看Udi Dahan在Reliable Messaging.

上的演示文稿

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

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

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

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

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

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