溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

WCF簡(jiǎn)單教程(6) 單向與雙向通訊

發(fā)布時(shí)間:2020-06-14 11:01:19 來(lái)源:網(wǎng)絡(luò) 閱讀:5703 作者:BoyTNT 欄目:編程語(yǔ)言

第六篇:?jiǎn)蜗蚺c雙向通訊

項(xiàng)目開(kāi)發(fā)中我們時(shí)常會(huì)遇到需要異步調(diào)用的問(wèn)題,有時(shí)忽略服務(wù)端的返回值,有時(shí)希望服務(wù)端在需要的時(shí)候回調(diào),今天就來(lái)看看在WCF中如何實(shí)現(xiàn)。

先看不需要服務(wù)端返回值的單向調(diào)用,老規(guī)矩,直接上代碼,再解釋。

1、服務(wù)端

契約接口中增加一個(gè)Sleep方法:

  1. using System;  
  2. using System.ServiceModel;  
  3. using System.Text;  
  4.   
  5. namespace Server  
  6. {  
  7.     [ServiceContract(Namespace="WCF.Demo")]  
  8.     public interface IData  
  9.     {  
  10.         [OperationContract]  
  11.         string SayHello(string userName);  
  12.  
  13.         /// <summary> 
  14.         /// IsOneWay = true 表明這是一個(gè)單向調(diào)用,注意返回值是void,因?yàn)榧热皇菃蜗蛘{(diào)用,客戶(hù)端肯定不會(huì)等待接收返回值的 
  15.         /// </summary> 
  16.         [OperationContract(IsOneWay = true)] 
  17.         void Sleep(); 
  18.     }  


對(duì)應(yīng)的實(shí)現(xiàn)類(lèi)中,我們來(lái)實(shí)現(xiàn)這個(gè)方法:

  1. using System;  
  2. using System.Text;  
  3.   
  4. namespace Server  
  5. {  
  6.     public class DataProvider : IData  
  7.     {  
  8.         public string SayHello(string userName)  
  9.         {  
  10.             return string.Format("Hello {0}.", userName);  
  11.         }  
  12.  
  13.         /// <summary> 
  14.         /// 實(shí)現(xiàn)Sleep方法,暫時(shí)不做任何事情,只是睡眠5秒 
  15.         /// </summary> 
  16.         public void Sleep() 
  17.         { 
  18.             Thread.Sleep(5000); 
  19.         } 
  20.     }  
  21. }  

App.config就不再列出來(lái)了,里面用的是一個(gè)netTcpBinding的endpoint。


2、客戶(hù)端

首先別忘了客戶(hù)端的契約要與服務(wù)端保持一致,App.config也不列出來(lái)了,里面有對(duì)應(yīng)的endpoint。主要是調(diào)用的代碼:

  1. using System;  
  2. using System.ServiceModel;  
  3. using System.ServiceModel.Channels;  
  4.   
  5. namespace Client  
  6. {  
  7.     class Program  
  8.     {  
  9.         static void Main(string[] args)  
  10.         {  
  11.             var proxy = new ChannelFactory<Server.IData>("DataService").CreateChannel();  
  12.  
  13.             //先調(diào)用SayHello方法  
  14.             Console.WriteLine(proxy.SayHello("WCF"));  
  15.             //調(diào)用一下Sleep方法,按我們的設(shè)想,它應(yīng)該是異步的,所以不會(huì)阻塞后面的調(diào)用 
  16.             proxy.Sleep(); 
  17.             //再調(diào)用一次SayHello方法  
  18.             Console.WriteLine(proxy.SayHello("WCF"));  
  19.             //關(guān)閉連接  
  20.             ((IChannel)proxy).Close();  
  21.     }  

按我們的設(shè)想,兩次SayHello調(diào)用之間應(yīng)該沒(méi)有延遲,因?yàn)镾leep是異步的嘛,編譯運(yùn)行一下,結(jié)果……  中間卡住了5秒,這是為什么呢?

這其中涉及到一個(gè)并發(fā)模型的問(wèn)題,默認(rèn)情況下,WCF以單線(xiàn)程模型對(duì)外提供服務(wù),也就是說(shuō),只能一個(gè)一個(gè)處理請(qǐng)求,即使是一個(gè)OneWay的單向調(diào)用,也只能等它處理完后才會(huì)接著處理后面的SayHello請(qǐng)求,所以會(huì)卡5秒。

并發(fā)模式有以下三種,MSDN上的介紹有點(diǎn)復(fù)雜,我給簡(jiǎn)化一下:

Single:?jiǎn)尉€(xiàn)程調(diào)用,請(qǐng)求只能一個(gè)一個(gè)處理;

Reentrant:可重入的單線(xiàn)程調(diào)用,本質(zhì)仍是單線(xiàn)程,處理回調(diào)時(shí),回調(diào)請(qǐng)求會(huì)進(jìn)入隊(duì)列尾部排隊(duì);

Multiple:多線(xiàn)程調(diào)用,請(qǐng)求是并發(fā)的響應(yīng)的;


調(diào)置服務(wù)并發(fā)模型是在契約的實(shí)現(xiàn)類(lèi)上,我們?yōu)镈ataService類(lèi)加一個(gè)Attribute:

  1. /// <summary> 
  2. /// 用ServiceBehavior為契約實(shí)現(xiàn)類(lèi)標(biāo)定行為屬性,此處指定并發(fā)模型為ConcurrencyMode.Multiple,即并發(fā)訪(fǎng)問(wèn) 
  3. /// </summary> 
  4. [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)] 
  5. public class DataProvider : IData 
  6.     //略 


這回再編譯運(yùn)行一下,連續(xù)打出了2行 Hello WCF,中間不再阻塞了。

 

現(xiàn)在我們?cè)賮?lái)看看雙向通訊的問(wèn)題。雙向通訊可以基于HTTP、TCP、Named Pipe、MSMQ,但要注意,basicHttpBinding和wsHttpBinding不行,要換用wsDualHttpBinding,它會(huì)創(chuàng)建兩個(gè)連接來(lái)進(jìn)行雙向通訊。至于TCP,它天然就是雙向通訊的。

1、服務(wù)端

服務(wù)契約要進(jìn)行修改,增加關(guān)于回調(diào)的契約:

  1. using System; 
  2. using System.ServiceModel; 
  3. using System.ServiceModel.Description; 
  4.  
  5. namespace Server 
  6.     /// <summary> 
  7.     /// 增加了CallbackContract的標(biāo)識(shí),用于指明針對(duì)此服務(wù)契約的回調(diào)契約是IDataCallback 
  8.     /// </summary> 
  9.     [ServiceContract(Namespace = "WCF.Demo", CallbackContract = typeof(IDataCallback))] 
  10.     public interface IData 
  11.     { 
  12.         [OperationContract] 
  13.         string SayHello(string userName); 
  14.  
  15.         [OperationContract(IsOneWay = true)] 
  16.         void Sleep(); 
  17.     } 
  18.  
  19.     /// <summary> 
  20.     /// 定義服務(wù)回調(diào)契約,注意它沒(méi)有契約標(biāo)識(shí),只是個(gè)一般接口 
  21.     /// </summary> 
  22.     public interface IDataCallback 
  23.     { 
  24.         /// <summary> 
  25.         /// 定義一個(gè)回調(diào)方法,由于回調(diào)不可能要求對(duì)方再響應(yīng),所以也標(biāo)識(shí)成OneWay的調(diào)用,同樣不需要有返回值 
  26.         /// </summary> 
  27.        [OperationContract(IsOneWay = true)] 
  28.        void SleepCallback(string text); 
  29.     } 


對(duì)應(yīng)的契約實(shí)現(xiàn)類(lèi)要修改一下:

  1. using System; 
  2. using System.ServiceModel; 
  3. using System.ServiceModel.Description; 
  4. using System.Threading; 
  5. using System.Net; 
  6.  
  7. namespace Server 
  8.     [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)] 
  9.     public class DataProvider : IData 
  10.     { 
  11.         public string SayHello(string userName) 
  12.         { 
  13.             string.Format("Hello {0}.", userName); 
  14.         } 
  15.  
  16.         public void Sleep() 
  17.         { 
  18. //先睡5秒
  19.             Thread.Sleep(5000); 
  20.  
  21. //用OperationContext.Current來(lái)獲取指定類(lèi)型的回調(diào)對(duì)象 
  22.             var callback = OperationContext.Current.GetCallbackChannel<IDataCallback>(); 
  23. //回調(diào)SleepCallback方法,并傳遞參數(shù) 
  24.             callback.SleepCallback("睡醒了"); 
  25.         } 
  26.     } 


2、客戶(hù)端

仍然提醒一下別忘了把新的服務(wù)契約更新到客戶(hù)端??蛻?hù)端的調(diào)用要調(diào)整一下:

  1. using System;  
  2. using System.ServiceModel;  
  3. using System.ServiceModel.Channels;  
  4.   
  5. namespace Client  
  6. {  
  7.     class Program  
  8.     {  
  9.         static void Main(string[] args)  
  10.         {  
  11.             //定義一個(gè)實(shí)現(xiàn)回調(diào)接口的類(lèi)實(shí)例 
  12.             var context = new DataCallbackImp(); 
  13.             //創(chuàng)建代理的時(shí)候變了,要用DuplexChannelFactory,因?yàn)镮Data契約已經(jīng)標(biāo)識(shí)了有回調(diào),所以必須要用支持雙向通訊的ChannelFactory,傳入剛才創(chuàng)建的回調(diào)實(shí)例 
  14.             var proxy = new DuplexChannelFactory<Server.IData>(context, "DataService").CreateChannel();  
  15.  
  16.             //調(diào)用Sleep 
  17.             proxy.Sleep(); 
  18.             //調(diào)用SayHello方法  
  19.             Console.WriteLine(proxy.SayHello("WCF"));  
  20.  
  21.             //等待按任意鍵,先不要關(guān)連接 
  22.             Console.ReadKey(); 
  23.             ((IChannel)proxy).Close();  
  24.     }  
  25.  
  26.     /// <summary> 
  27.     /// 實(shí)現(xiàn)回調(diào)接口中的類(lèi),圖省事寫(xiě)到這里了 
  28.     /// </summary> 
  29.     class DataCallbackImp : Server.IDataCallback 
  30.     { 
  31.         /// <summary> 
  32.         /// 實(shí)現(xiàn)SleepCallback方法 
  33.         /// </summary> 
  34.         public void SleepCallback(string text) 
  35.         { 
  36.             Console.WriteLine("收到回調(diào)了:" + text); 
  37.         } 
  38.     } 


編譯運(yùn)行,屏幕先顯示一行“Hello WCF.”,過(guò)5秒后顯示“收到回調(diào)了:睡醒了”。

 

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI