2012-07-31 71 views
2

之间的通信我有一个WCF客户端,对于订单确认和WCF服务,两种方式问:WCF - 两种方法

1)UpdateOrder - 更新订购数据库中的数据(UpdateOrder调用来自外部服务)
2)GetConfirmationResult - 持有结果返回,直到订单状态从挂起变为其他。

问题是,在WCF中如何使UpdateOrder通知GetConfirmationResult,订单状态已更改?

更新:如果我可以将InstanceContextMode作为每次调用保留,那么最好。

更新2:假设可能的订单状态为待定,确认,拒绝。 ConfirmOrder可能会将订单状态更改为已确认或已拒绝,GetConfirmationResult不应返回结果,直到通过确认订单进行更改。

更新3:我已经改变了图像的顺序来显示整个堆栈。

enter image description here

+0

是您的确认订单方式吗?你使用什么交通工具? – 2012-07-31 07:25:15

+0

@hugh:确认订单方法是一种方式,传输是https。 – Giedrius 2012-07-31 07:36:01

+1

另外,您的客户端是否与您的服务在同一网络上进行GetConfirmationResult调用? – 2012-07-31 08:40:04

回答

1

目前我已经使用EventWaitHandle解决了这个问题 - 不确定它是否是最好的方式,但它看起来很干净,很好地支持超时并且是相当可测试的。

public class TestClass 
{ 
    public static event OrderUpdateHandler UpdatedOrder; 

    public void UpdateData(Order order) 
    { 
     // ... 

     OnOrderUpdated(args); 
    } 

    public Order GetConfirmedOrder(int id, TimeSpan waitToConfirm) 
    { 
     var order = GetOrderFromDatabase(); 

     if (order.Status == OrderStatus.Pending) 
     { 
      var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset); 

      UpdatedOrderHandler waiter = (s, e) => 
      { 
       if (e.Order.Id == id) 
       { 
        order = e.Order; 
        eventHandle.Set(); 
       } 
      }; 

      UpdatedOrder += waiter; 

      if (!eventHandle.WaitOne(waitToConfirm)) 
      {     
       return order; 
      } 

      OrderUpdated -= waiter; 
     } 

     return order; 
    } 
} 
+0

不错!如果这是您的解决方案,请标记为答案。干杯 – 2012-09-04 07:20:51

3

你说你有一个数据库备份该服务器。然后,它会像这样,半伪一样简单:

public YourService : YourServiceInterface 
{ 
    public void UpdateOrder(Order order) 
    { 
     using (context = new DatabaseContext()) 
     { 
      context.Orders.Where(o => o.ID == order.ID).First().IsConfirmed = order.IsConfirmed; 
      context.SaveChanges(); 
     } 
    } 

    public Boolean? GetConfirmationResult(Order order) 
    { 
     using (context = new DatabaseContext()) 
     { 
      return context.Orders.Where(o => o.ID == order.ID).First().IsConfirmed; 
     } 
    } 
} 

你必须坚持它,因为你提的每一个呼叫实例模式。您不能保留static List<Order>以包含您的挂单,只需将它们保存到您的数据库并将它们添加为挂起,未批准。

+0

我已经提到过,GetConfirmationResult会保留结果,直到订单状态从挂起状态变为其他状态时为止,所以在您的解决方案中,如果我查询GetConfirmationResult并且ConfirmOrder尚未更新订单,它将返回结果,尽管它不应该。我已更新问题以使其更清楚。 – Giedrius 2012-07-31 08:25:48

+0

@Giedrius我不知道你的意思是_“它会返回结果,尽管它不应该”_。订单尚未确认时,您希望它做什么?在我的情况下,它返回'false'。 – CodeCaster 2012-07-31 08:29:52

+0

Thread.Sleep我猜想:)事情是,Web应用程序需要这样的结果,所以有几种解决方案 - 我们可以重复对wcf的请求,直到我们得到表示确认已发生的结果或者我们可以延迟在wcf侧发布结果。 – Giedrius 2012-07-31 08:32:30

1

听起来像你的问题是基于这样一个事实,即订单状态在特定时间发生变化,并且仅当该阶段发生变化时才与服务消费者了解新订单状态有关。

这是使用消息传递的完美场景。

与您的wcf客户端调用服务不同,服务应该在订单状态更改时向客户端发送消息。然后,客户端可以处理该消息(在您的情况下为ConfirmationResult消息)。

您可以通过使用netMsmqBinding并在接受msmq消息的客户端上托管一个操作来完成此操作。

[OperationContract] 
void ReceiveConfirmationResult(ConfirmationResult result); 

这非常简单,因为它完全消除了问题的根源。作为额外的好处,服务操作GetConfirmationResult()可以被删除,因为它不再需要。

UPDATE

我想你误会,因为根据您的最新问题的更新这是使用排队一个更强大的情况下。

事件的顺序:

  1. 订单确认收到
  2. 服务器状态改变
  3. 服务器应用逻辑摸出如果状态变化应当被发送到客户
  4. 服务器发送向客户发送描述状态变化的消息
+0

我完全同意你,但仍不明白为什么要尝试避免长时间轮询(或http://en.wikipedia.org/wiki/Comet_(programming)) – Giedrius 2012-07-31 11:06:57

+0

因为它很复杂。排队真的很简单。此外,您还获得其他好处,例如可用性和耐用性。如果你不得不通过互联网,那么我会同意,彗星或其他长轮询策略将是最好的方式。 – 2012-07-31 11:10:11

+0

我已经做了一些思考,我认为在我的情况下使用消息只会将问题从WCF应用程序移动到客户端(ASP.NET MVC)应用程序,我会尝试更新我的问题以显示它为什么如此。 – Giedrius 2012-08-01 05:17:26