WCF服務注意問題之-回調

WCF服務注意問題之-回調

 

在使用服務時雖然一般是客戶端向服務端請求服務,但有些時候也需要服務端向客戶端進行通知(Notify),在CS的程序中尤爲常見,在出現WCF之前,Remoting中使用回調是大費周章的一件事情,需要建立單獨的偵聽類,並且要處於獨立的程序集中才行,在WCF中大大簡化了回調過程,但是也有一些需要特別注意的地方,如果不注意回調也不是那麼容易的,先看一個簡單的回調代碼:

 

一:配置屬性聲明:

 

服務接口:

   [ServiceContract(CallbackContract = typeof(IChartCallBack))]    public interface IChart
    {

        [OperationContract]
        void Join(string name);

        [OperationContract]
        void Leave(string name);
        [OperationContract]
        void Speek(string namestring desnamestring message          );
    }

服務端實現:

  [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant,
     InstanceContextMode = InstanceContextMode.PerCall)]
public abstract class ChartIChart
{
        public void Join(string name)
        {
             //……code
             IChartCallBack callback = OperationContext.Current.GetCallbackChannel<IChartCallBack>();
if (callback != null)
 {
                callback.NotifyJoin(name);  //通知客戶端
           }
    }
    //剩餘代碼
}

 

回調接口:

[ServiceContract]
    public interface IChartCallBack
    {
     [OperationContract(IsOneWay = true)]
        void NotifyJoin(string name);
     [OperationContract(IsOneWay = true)]
        void NotifyLeave(string name);
    [OperationContract(IsOneWay = true)]
        void SpeekTo(string namestring message);

     }

客戶端實現:

[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant,UseSynchronizationContext=false)]
    public  class ClientIChartCallBack //
實現了聊天回調窗口

    {
        public void NotifyJoin(string name)
        {
   Console.WriteLine(name + ” 已加入”);
}

     }

上面的代碼都很簡單,用起來也極爲簡便,但是要注意的地方還是很多,如果不注意這些問題就會出差錯,如上面的代碼所示回調基本上是在聲明式代碼中完成的,屬性又有不同的選項,不同的選項用處也不一樣,要使的服務端能夠回調客戶端代碼,有以下幾種方式:

1.     配置服務多線程訪問

即設置ServiceBehavior屬性的ConcurrencyMode值爲Mutiple,這樣服務類就允許多線程訪問了,但是多線程訪問會代碼同步問題,所以需要處理好同步問題;

2.     回調重入

配置ServiceBehavior屬性的ConcurrencyMode值爲Reentrant,服務成爲單線程訪問,在回調發生時可衝入;

3.     單向回調

在回調接口中的操作契約中設置IsOneWaytrue,設置爲單向調用,也可進行回調

如果在使用回調時不遵循這3種方式,回調時會出現異常,無法完成回調工作。

 

二:客戶端處理回調的問題:

 

由於回調是服務端異步調用,因此會出現調用超時,跨線程訪問的問題,如果不認清這些問題的本質,就開始編寫代碼,往往回調會不成功的,如果使用控制檯工程,不使用UI,則跨線程訪問UI的問題不會出現,但是超時依然會出現。

1.     超時問題

如將

Console.WriteLine(name + ” 已加入”);

這行代碼改成

MessageBox.Show(name);

如果長時間不響應MessageBox,則會拋出異常,所以在回調處理中如果不標記IsOneWaytrue,則儘量不要在處理中採用耗時代碼,以免超時。 

2.     WinFrom中回調代碼訪問UI的問題

   由於回調線程和UI的線程並非同一線程,因此在訪問UI時就會出現問題,要解決這一問題,和多線程訪問UI是一致的,將訪問代碼封送到UI線程中來處理,如使用Control.Invoke()函數,或者使用SynchronizationContext同步上下文來完成UI訪問任務。

3.     WPF中訪問UIElement的問題

   WPF已經不採用Windows消息循環系統了,而採用自行設計的消息系統,因此WPF中處理這種問題和WinForm並不相同,UIElement不在提供Invoke函數來封送代碼了,而且也沒有SynchronizationContext上下文,但是WPF提供了Dispatcher對象,通過Dispatcher.CurrentDispatcher來獲取當前線程(UI線程)的消息分發器對象,Dispatcher有一個Invoke函數,該函數可以實現將另一線程中的代碼封送到當前線程中來執行,這樣就可以解決跨線程訪問UI的問題。
 

三:安全問題

 

   上面的代碼在單機中運行是沒有任何問題的,但是將客戶端服務端分到兩臺PC機中,問題就會出來了,無論調用服務也好回調也好,都會有安全問題,因此需要對安全問題進行配置,安全問題是一個大話題,這裏就不細說,爲了代碼能在多臺機器中運行,最簡單的就是不使用安全驗證,配置文件如下所示:

在配置文件中增加bindings節:

 <bindings>
      <netTcpBinding>
        <binding name="TcpSecurity">
          <security mode="None"> <!--
不採用安全措施-->
            <transport clientCredentialType="None" protectionLevel="None"/>
          </security>
        </binding>
      </netTcpBinding>
  </bindings>

這裏使用的是netTcpBinding 如果使用別的綁定,則增加特定綁定的配置代碼,在終結點中增加bindingConfiguration屬性,並將值指向binding的名稱,如

   <endpoint address="net.tcp://localhost:8000/chart"
                  binding="netTcpBinding"
                  contract="fzgk.IChart"
                  
bindingConfiguration="TcpSecurity"
                  name="TcpBinding"/>
客戶端也一樣增加這些配置項,再次運行程序就不會出現安全問題了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章