域事件是否可以向UI层返回反馈信息



我对DDD应用程序还是相当陌生的。我正在阅读Eric Evan的"领域驱动设计",并阅读了Udi Dahan的"通过领域事件拯救采用领域模型模式"。。。

但有一件事我无法理解,那就是如何将有关域事件成功或未成功完成的信息作为反馈返回给用户(即UI层)?

例如,我们可以有以下应用层代码:

// Application Layer
public void SubmitOrder(OrderData data)
{ 
var customer = GetCustomer(data.CustomerId);
var shoppingCart = GetShoppingCart(data.CartId);
customer.Purchase(shoppingCart);
}
// Domain Model
public class Customer
{ 
public void Purchase(ShoppingCart cart)
{
// something done with the cart...
DomainEvents.Raise(new CustomerPurchaseCompleted() { Customer = this, ShoppingCart = cart });
}
}

现在假设我们有以下事件处理程序,如果客户指定了电子邮件地址,它会向客户发送确认电子邮件。

public class CustomerPurchaseCompletedHandler : Handles<CustomerPurchaseCompleted>
{ 
public void Handle(CustomerPurchaseCompleted args)
{
if (args.Customer.Email != null) {
// send email to args.Customer
}
else {
// report that no email will be sent...
}
}
}

我的问题是:我应该如何向UI层"弹出"一条反馈消息,说不会因为客户没有设置电子邮件而发送电子邮件?

我今天看到的选项是:

  1. 让UI层检查客户是否有电子邮件,并相应地发出消息。这似乎很糟糕,因为UI会意识到应该发送电子邮件,这是应用程序级别的信息。

  2. 当没有电子邮件时抛出一个UserHasNoEmailException,并在某个地方捕获该信息。这真的很糟糕,因为不应该使用异常来返回信息,而且这不是致命错误,也不应该中止其他处理程序。。。

  3. SubmitOrder()返回一些List<FeedbackMessage>。这将需要更改Purchase()DomainEvents.Raise()方法才能返回此列表。这导致域模型知道UI应该显示什么而不应该显示。。。

这三个选项似乎都不太好,也不太实用。那么DDD专家是如何做到的呢?

谢谢。

另一个选项是实现另一个事件处理程序,它专门负责通知UI客户没有电子邮件地址。因此,如果CustomerPurchaseCompletedHandler没有发送电子邮件,该处理程序将通知UI。这个处理程序将是UI层的一部分。通知UI的一个好方法是向这个处理程序中注入一个事件聚合器:

public class NotifyingCustomerPurchaseCompletedHandler : Handles<CustomerPurchaseCompleted>
{ 
public IEventAggregator Events { get; set; }
public void Handle(CustomerPurchaseCompleted args)
{
if (args.Customer.Email == null) {
// notify UI
this.Events.GetEvent....
}
}
}

总的来说,这基本上是方法1。的确,UI层现在知道要发送电子邮件,但是UI必须知道这一点,因为它需要呈现一条声明不发送电子邮件的消息。显示消息是一个UI问题,通过将处理程序实现作为UI层的一部分,可以保持它的原样。这种方法的问题是,你要检查客户是否有两次电子邮件。此外,电子邮件的发送与UI通知没有直接联系。

另一种选择是引入另一个事件,表示没有电子邮件的客户的购买已经完成。然后UI可以订阅此事件。这种方法的缺点是,您专门为UI需求创建了一个事件,而不是表达领域知识。

事件不应报告反馈。事件ARE反馈。

在这种情况下,Email是一个业务需求。因此,如果没有指定电子邮件,customer.Purchase(shoppingCart);应该真的抛出异常。

但假设实际的电子邮件发送失败。我通常做的是创建一个用于通知的域模型。所以我这样做:

var notification = new Notification(userId, "Failed to deliver receipt to user.");
notificationRepository.Save(noitification);

这又将生成可由UI拾取的NotificationCreated事件。

最新更新