2013-04-17 144 views
2

我正在將服務構建到現有應用程序中,每個服務的構建目的是僅由一個客戶端使用,客戶端和服務器使用雙工通信通道進行設置。WCF服務之間的通信

限制

  1. 我沒有,現有的基礎設施
  2. 我不能使用可共享會話

要求重新設計的選項:

  1. 我需要能夠在客戶端服務之間進行通信(例如,如果用戶點擊某個項目並希望分享該項目無論出於何種原因,客戶端可能無法處理「共享」功能,並需要將其傳遞給另一客戶端進行處理 - 這必須通過服務完成)
  2. 客戶端之間的通信必須進行由服務。

爲了最初得到這個工作,我直接在兩個客戶端之間建立IPC通道(netNamedPipeBinding),但我被告知通過服務器發送所有內容。在這種情況下,「服務器」在大多數情況下與客戶端運行在同一臺機器上,所以我想出了這個非常粗略的概念驗證(參見下面的代碼塊)。

問題:當一個方法被調用的訂閱服務,針對當前服務中的操作環境(在其內部被調用的方法)爲空 - 這留下的服務沒有任何方法來調用返回給客戶端

我用的是考慮朱瓦爾·洛的發佈/訂閱框架,他在ServiceModelEx框架提供,但它似乎沒有必要在所有的客戶端已經有他們自己和他們各自的服務之間的雙向通信設置...如此的意圖僅僅是添加一個簡單的發佈/訂閱層,它在概念上位於這些服務的「底層」,並且可以與任何關心訂閱的人交談。

歡迎提供建議和建設性的批評!


public static class SubscriptionManager<TEventArgs> 
    where TEventArgs : class 
{ 
    private static ConcurrentDictionary<int, Action<TEventArgs>> _subscribers = 
     new ConcurrentDictionary<int, Action<TEventArgs>>(); 

    // sessionId is NOT the WCF SessionId 
    public static void FireEvent(int sessionId, TEventArgs eventArgs) 
    { 
     var subscribers = _subscribers.Where(s => s.Key == sessionId); 
     var actions = subscribers.Select(keyValuePair => keyValuePair.Value); 

     foreach (var action in actions) 
      action.BeginInvoke(eventArgs, action.EndInvoke, null); 
    } 

    public static void Subscribe(int sessionId, Action<TEventArgs> eventHandler) 
    { 
     _subscribers.TryAdd(sessionId, eventHandler); 
    } 

    public static Action<TEventArgs> Unsubscribe(int sessionId) 
    { 
     Action<TEventArgs> eventHandler; 
     _subscribers.TryRemove(sessionId, out eventHandler); 
     return eventHandler; 
    } 
} 
+0

你能格式化你的問題。很難閱讀。 – I4V

+0

完全有效:) ...在一個會議現在...將重新格式化它很快 – Jordan

+0

格式化(加入剩下的滿足最低要求的性格,我現在是遠遠超過) – Jordan

回答

1

所以第一關,好像我是執行模式可以被歸類爲Mediator Pattern

所以我通過傳入FireEvent調用服務的當前實例上下文來解決這個問題,在我的情況下,它應該與訂閱服務具有相同的上下文。

我在這裏處理的情況是,在同一用戶的上下文,並從同一臺客戶機運行斷開連接的客戶端應用程序,但(按客戶要求),他們必須通過服務層溝通。

我開始沿着他的ServiceModelEx庫使用WCF同步上下文和Juval Lowy的類,但是我被綁定到一個實現,其中Ninject WCF擴展阻礙了這一點。

因此該解決方案將基於自己的實現進行調整,但給你的我是如何得到這個工作的想法,這是我更新FireEvent方法的要點:

public static void FireEvent(int sessionId, TData eventData, InstanceContext context) 
{ 
    var subscribers = Subscribers.Where(s => s.Key == sessionId); 

    var eventArguments = subscribers.Select(kvp => kvp.Value); 

    foreach (var argument in eventArguments) 
    { 
     // set data associated with the event 
     argument.SetData(eventData); 

     NinjectInstanceProvider instanceProvider = null; 
     Object instance = null; 

     try 
     { 
      // get a "synchronized instance" of the service of type defined by event args 
      instanceProvider = new NinjectInstanceProvider(argument.ServiceType); 
      instance = instanceProvider.GetInstance(context); 

      // get the method from our "synchronized instance" 
      // filter by argument types so we don't run into any issues with ambiguity 
      var argumentTypes = new[] { typeof (TEventArgs) }; 
      var method = instance.GetType().GetMethod(argument.Callback, argumentTypes); 

      // our method arguments 
      var arguments = new object[] { argument }; 

      // invoke the method on our "synchronized instance" 
      method.Invoke(instance, arguments); 

      // release the instance 
      instanceProvider.ReleaseInstance(context, instance); 
     } 
     catch 
     { 
      // log 
     } 
     finally 
     { 
      if(provider != null) 
      { 
       if(instance != null) { instanceProvider.ReleaseInstance(context, instance); } 
      } 
     } 
    } 
}