我正在尝试使用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
}
答案 0 :(得分:3)
事件处理程序是否应该在命令处理程序中注册?
除非它们是动态的,否则不是。您通常会在应用程序CompositionRoot中将它们连接起来。我们的想法是,当您的应用加载时以及“准备好”之前,所有接线都会发生。
您在哪里注册命令处理程序?您应该在同一个地方注册您的事件处理程序。
[UPDATE]
有关示例,请参阅https://github.com/gregoryyoung/m-r/blob/master/CQRSGui/Global.asax.cs
答案 1 :(得分:0)
您应该查看Udi Dahan在Reliable Messaging.
上的演示文稿典型的体系结构通常包含一些消息队列/事件总线。您的事件处理程序在启动时会使用总线注册事件订阅。正如@tomliversidge指出的那样,通常会在组合根目录中。
将更改保存到聚合时,还会保存该命令引发的DomainEvent。这两个写入都发生在同一个事务中,在同一个记录簿中。所以他们都成功了,或者他们都失败了。
如果交易失败,那么数据模型没有改变,没有人需要通知任何事情 - 像往常一样向客户报告失败并继续你的生活。
如果命令成功,那么我们需要安排要发布的事件。这是一种基本的异步操作 - 事件处理程序对记录簿的任何其他写入都将在他们自己的事务中。
自然要做的是让命令处理程序安排任务将事件发布到总线。调度完任务后,命令处理程序返回(在任务运行时并不关心)。
但由于事件发生在记录簿中,您可以随时再次发布它们。