问题
I am trying to model purchasing domain using CQRS & DDD, i know that i raise events in domain but i don't know where to Register them when i am using commands. Should event handlers be registered in command handlers? or maybe i misunderstood something. this is my process can you help model it right way?
Finalize purchase order Command is given, than command handler finalizes order (gets order from repository, changes its state and saves back to db), order finalized event occurs in domain model, than event handler finds this order using id with its line items, find it suppliers contact info(may be email or even external service) and notifies him about new purchase order.
My Commands & Command Handlers are in Application Layer(Event Handlers should be here also?). Domain Model, Events and IRepositories in Domain Layer. Repository Implementations in Infrastructure Layer.
Domain Model (skipped most of properties):
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 Command
public class FinalizePurchaseOrder : ICommand
{
public FinalizePurchaseOrder (int purchaseOrderID)
{
PurchaseOrderID = purchaseOrderID;
}
public int PurchaseOrderID { get; private set; }
}
Command Handler
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);
}
}
Event and Event Handler looks like this:
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
}
回答1:
Should event handlers be registered in command handlers?
Not unless they are dynamic, no. You would typically wire them up in your application's CompositionRoot. The idea being that all the wiring up takes place when your app loads and before it is "ready".
Where are you registering your command handlers? You should be registering your event handlers in the same place.
[UPDATE]
For an example, see https://github.com/gregoryyoung/m-r/blob/master/CQRSGui/Global.asax.cs
回答2:
You should review Udi Dahan's presentation on Reliable Messaging.
The typical architecture usually includes some flavor of message queue/event bus. Your event handlers, on startup, register their subscriptions to events with the bus. As @tomliversidge points out, that will generally be in the composition root.
When you save the changes to your aggregates, you also save the DomainEvents that have been raised by that command. Both of these writes occur in the same transaction, in the same book of record. So they both succeed or they both fail.
If the transaction fails, then the data model hasn't changed, and nobody needs to be notified of anything -- report the failure to the client as usual and get on with your life.
If the command succeeds, then we need to arrange for the events to be published. This is a fundamentally asynchronous operation -- any other writes to the book of record by event handlers will be within their own transactions.
The natural thing to do is to have your command handler schedule an task to publish the events to the bus. Having scheduled the task, the command handler returns (it doesn't really care when the task runs).
But since the events are in the book of record, you can publish them again any time you like.
来源:https://stackoverflow.com/questions/38482387/register-eventhandler-in-cqrs