2012-06-20 13 views
0

背景 我創建它使用一個自定義庫的ASP.net應用程序(尚未公開發布,但很快)在提供長輪詢處理器向一個JavaScript客戶端jQuery的。客戶端將調用處理程序,等待處理程序返回一些數據,顯示它,然後再次敲擊處理程序...清洗,漂洗,重複。簡單的跨應用數據和事件通過在C#

處理程序的工作是接受請求,將其粘貼到集合中(通常爲List<>),並等待包含數據的事件返回到等待請求。我已經測試過了,在我的服務器上使用一個靜態類中的簡單事件,這一切都正常。

問題 爲了使被所有客戶端接收的消息,在我的服務器上的所有應用程序域,我創建了一個簡單的C#控制檯應用程序 - 這是在後臺運行,並提供一個DataContract在WCF(NamedPipe )。然後,我在ASP.net中創建了一個客戶端對象,它可以通過WCF界面與控制檯應用程序交談。

我可以同步將郵件推入/緩存到我的緩存 - 這工作正常。但是,當我嘗試在WCF合同上使用異步模式時,在將IAsyncResult返回到BeginMethod之後,會立即觸發EndMethod

我看不出有什麼不對 - Google有足夠的資源顯示弱示例,他們不幫助。

我想要什麼 他們是否通過數據契約綁定到通過WCF的事件?這樣我就可以附加到事件上,並完成它。進入緩存的新消息觸發我的事件,這會觸發異步處理程序返回所有等待請求。

這是可能的,如果有的話是否有任何樣品/教程/例子?

代碼要按照...

回答

2

我知道這是可能的,我已經做到了這一點,並且知道有這個在那裏有限的信息(我計劃很快建立一個博客文章)。基本上,您需要創建Subscribe/Unsubscribe WCF方法,這將保持您的端口打開。

服務器代碼應該是這樣的:

[ServiceContract(SessionMode = SessionMode.Required, 
    CallbackContract = typeof(IProcessorCallBack))] 
public interface IProcessor 
{ 
    [OperationContract] 
    Boolean SubscribeToEvents(); 

    [OperationContract] 
    Boolean UnsubscribeToEvents(); 
} 

public interface IProcessorCallBack 
{ 
    [OperationContract(IsOneWay = true)] 
    void OnEvent(EventArgs args); 
} 

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)] 
public class DDSpeechMikeProcessor:IProcessor 
{ 
    private readonly List<IProcessorCallBack> _eventListeners = 
     new List<IProcessorCallBack>(); 

    public bool SubscribeToEvents() 
    { 
     var listenerToCallBacks =  
      OperationContext.Current.GetCallbackChannel<IProcessorCallBack>(); 
     if(!_eventListeners.Contains(listenerToCallBacks)) 
      _eventListeners.Add(listenerToCallBacks); 
    } 

    public bool UnsubscribeToEvents() 
    { 
     var listenerToCallBacks = 
      OperationContext.Current.GetCallbackChannel<IProcessorCallBack>(); 
     if (_eventListeners.Contains(listenerToCallBacks)) 
      _eventListeners.Remove(listenerToCallBacks); 
    } 

    //This is your server listening for the main event 
    //which it will pass on to all listeners 
    void OnEvent(EventArgs args) 
    { 
     foreach(var listener in _eventListeners) 
     { 
      try 
      { 
       listener.OnEvent(args); 
      } 
      catch (Exception exception) 
      { 
       RemoveListenerIfBadCommunication(listener, exception); 
      } 
     } 
    } 

    //If a listener did not unsubscribe before shutting down you will get exceptions 
    private void RemoveListenerIfBadCommunication(IProcessorCallBack listener, 
     Exception exception) 
    { 
     if (exception.GetType() == typeof(CommunicationException) 
      || exception.GetType() == typeof(CommunicationObjectAbortedException) 
      || exception.GetType() == typeof(CommunicationObjectFaultedException) 
     ) 
      _eventListeners.Remove(listener); 
    } 
} 

在您的客戶端代碼:

public class Client : IProcessorCallBack 
{ 
    DuplexChannelFactory<IProcessor> _processorFactory; 
    IProcessor _processor 
    void OpenProcessor() 
    { 
     _speechMikeProcessorFactory = new DuplexChannelFactory<IProcessor>(
       this, 
       new NetNamedPipeBinding(), 
       new EndpointAddress(baseUri + @"/" + HostName)); 
     _processor = _speechMikeProcessorFactory.CreateChannel(); 
     _processor.SubscribeToEvents(); 
    } 

    void OnEvent(EventArgs args) 
    { 
     //Do Stuff 
    } 
} 

讓我知道如果我需要更詳細

+0

這種方法確實解釋什麼像我打算那樣工作。在我的情況下需要一些小的調整,但校長是堅實的。 謝謝! – justacodemonkey