将IOrderSender注入域对象

时间:2013-10-25 06:19:40

标签: c# oop domain-driven-design domain-events

我一直在思考这个问题。一般来说,我试图远离注入服务到我的域名,但我有这种情况:

我有一个PurchaseOrder对象。此订单使用某些服务(电子邮件或Web服务)发送给供应商。发送订单后,应向发出订单的用户发送确认信息。

所以我意识到这是一个域事件将是实现发布PurchaseOrderMade事件的好方法。

然后我开始思考:

  

如果没有发送订单,订单是否真的有效?

您还没有订购,只是因为您决定这样做并将其写下来,但是订单是在您根据合同无条件地将其传送给供应商时订购的。

所以我重新考虑并认为这可能属于域名所以我应该通过向我的域注入IPurchaseOrderSender发送它,然后在成功交易后发布OrderMadeEvent并在EventHandler中发送确认。

原因是:

  1. 发送订单是流程的关键部分,可能导致状态发生变化(即设置订单发送的标志)
  2. 确认并不重要,如果失败,订单仍然完成,一切都按计划进行。
  3. 易于阅读,并且可以改变IOrderService的实现
  4. 问题是:

    1. 这真的很糟糕吗?
    2. 是否打破了DDD的原则?
    3. 你以前遇到过这种情况并以更好的方式解决了吗?
    4. 以下是代码:

              public void MakeOrder(PurchaseOrder order, IPurchaseOrderSender orderSender)
          {
              if(PurchaseOrders == null)
                  PurchaseOrders = new List<PurchaseOrder>();
              PurchaseOrders.Add(order);
      
              orderSender.Send(order);
              DomainEvents.Raise(new PurchaseOrderIsMade(){Order = order});
          }
      
          public interface IPurchaseOrderSender
      {
          void Send(PurchaseOrder order);
      }
      

1 个答案:

答案 0 :(得分:1)

我以前遇到过这个,这就是我做的:

使用远程过程调用拆分本地事务。

如果订单发送失败,我认为这不是什么大问题。在这种情况下,订单已下达但未设置为“已发送”或订单已回滚。如果未发送订单,则业务运营商可以进行干预,如果未下订单,则客户将进行调用。

但是,如果成功发送订单后交易出现问题,那就太烦人了。在这种情况下,如果订单被回滚,则干预更加困难,因为我们丢失了供应商的通知。通知通常包含供应商的订单标识符,因此我们可以在必要时使用此标识符取消订单。

所以我们决定使用消息传递 1)PlaceOrderService负责存储订单并发送消息 2)消息的消费者将订单发送给供应商并发送包含供应商通知的消息 3)通知消息的另一个消费者更新订单状态。

每个步骤只修改一个聚合或只调用遥控器。

希望这有帮助。

更新

  

1.如何在这里实现消息传递部分

我采用Eric Evans的dddsample,ApplicationEvents中提到的解决方案。它只是一个简单的接口和一个jms实现,类似于

    public void placeOrder(...) {// method in application service
        ....//order making
        orderRepository.store(order);
        applicationEvents.orderWasPlaced(order);//injected applicationEvents 
        //better move this step out of transaction boundary if not using 2pc commit
        //make the method returnning order and use decorator to send the message 
        //    placeOrder(...) {
        //        Order order = target.placeOrder(...);//transaction end here
        //        applicationEvents.orderWasPlaced(order);
        //        return order;
        //    }
    }

    public class JmsApplicationEvents implements ApplicationEvents {
        public void orderWasPlaced(Order order) {
             //sends the message using messaging api of your platform
        }
    }
  

2.我看到你提到供应商通知,但我们假设这是通过电子邮件完成的(这将是主要方案)我会   想知道交易是在没有错误的情况下进行的(即   没有smtp或连接失败),但不能依赖于响应   实际收到订单会改变什么吗?

嗯..我从来没有基于电子邮件建立交易应用程序,但这是我的建议:

  1. 如果您需要强大的一致性,邮件解决方案仍然适用。消息传递是事务性的,可能涉及全局事务,而电子邮件则不会。

  2. Messaging提供更多可用性(即使邮件服务器已关闭,您的订单也不会失败)和可扩展性(队列)。

  3. 在消息传递解决方案中,故障处理更加困难,通常需要补偿操作。并且用户更难以获得处理信息。例如,您必须通知用户订单处理的进度,因为以下步骤是异步的。如果供应商拒绝订单,则应向客户发送电子邮件。

  4. 但是,消息传递确实增加了额外的复杂性,并且需要您进行更多的构建和维护工作。你必须评估是值得花费的收益。实际上,我还在同步解决方案中构建了多个系统(它们不需要高吞吐量和可用性),它们在大多数情况下工作正常,但由于一年内连接问题,只有不到十个订单失败,所以它不是值得建立一个自动错误处理机制。