一、引言
在上一篇文章中介紹了WCF對Session的支持,在這篇文章中將詳細介紹WCF支持的操作。在WCF中,除了支持經典的請求/應答模式外,還提供了對單向操作、雙向回調操作模式的支持,此外還有流操作的支持。接下來將詳細介紹下這幾種操作,並實現一個雙向回調操作的例子。
二、WCF操作詳解
2.1 請求—應答操作
請求應答模式是WCF中默認的操作模式。請求應答模式指的是:客戶端以消息形式發送請求,它會阻塞客戶端直到收到應答消息。應答的默認超時時間為1分鍾,如果超過這一時間服務仍然沒有應答,客戶端就會獲得一個TimeOutException異常。WCF中除了NetPeerTcpBinding和NetMsmqBinding綁定,所有的綁定都支持請求—應答操作。
2.2 單向操作
單向操作是沒有返回值的,客戶端不關心調用是否成功。單向操作指的是:客戶端一旦發出調用請求,WCF會生成一個請求消息發送給服務端,但客戶端並不需要接收相關的應答消息。因此,單向操作不能有返回值,並且服務端拋出的任何異常都不會傳遞給客戶端。所以客戶端如果需要捕獲服務端發生的異常,此時不能把操作契約的IsOneWay屬性設置為true,該屬性的默認值為false。異常處理參考:如何在WCF進行Exception Handling。單向操作不等同於異步操作,單向操作只是在發出調用的瞬間阻塞客戶端,但如果發出多個單向調用,WCF會將請求調用放入服務端的隊列中,並在某個時間進行執行。隊列的存儲個數有限,一旦發出的調用個數超出了隊列容量,則會發生阻塞現象,此時調用請求無法放入丁烈,直到有其他請求被處理,即隊列中的請求出隊列后,產生阻塞的調用就會放入隊列,並解除對客戶端的阻塞。WCF中所有綁定都支持單向操作。WCF中實現單向操作只需要設置IsOneWay屬性為true即可。這里需要注意一點:由於單向操作沒有應答消息,因此它不能包含返回結果。
2.3 回調操作
WCF支持服務將調用返回給它的客戶端。在回調期間,服務成為了客戶端,而客戶端成為了服務。在WCF中,並不是所有的綁定都支持回調操作,只有具有雙向能力的綁定才能夠用於回調。例如,HTTP本質上是與連接無關的,所以它不能用於回調,因此我們不能基於basicHttpBinding和wsHttpBinding綁定使用回調,WCF為NetTcpBinding和NetNamedPipeBinding提供了對回調的支持,因為TCP和IPC協議都支持雙向通信。為了讓Http支持回調,WCF提供了WsDualHttpBinding綁定,它實際上設置了兩個Http通道:一個用於從客戶端到服務的調用,另一個用於服務到客戶端的調用。
回調操作時通過回調契約來實現的,回調契約屬於服務契約的一部分,一個服務契約最多只能包含一個回調契約。一旦定義了回調契約,就需要客戶端實現回調契約。在WCF中,可以通過ServiceContract的CallbackContract屬性來定義回調契約。具體的實現代碼如下所示:
// 指定回調契約為ICallback [ServiceContract(Namespace="http://cnblog.com/zhili/", CallbackContract=typeof(ICallback))] public interface ICalculator { [OperationContract(IsOneWay = true)] void Multiple(double a, double b); } // 回調契約的定義,此時回調契約不需要應用ServiceContractAttribute特性 public interface ICallback { [OperationContract(IsOneWay = true)] void DisplayResult(double x, double y, double result); }
在上面代碼中,回調契約不必標記ServiceContract特性,因為類型只要被定義為回調契約,就代表它具有ServiceContract特性,但仍然需要為所有的回調接口中的方法標記OperationContract特性。
2.4 流操作
在默認情況下,當客戶端與服務交換消息時,這些消息會被放入到接收端的緩存中,一旦接收到完整的消息,就立即被傳遞處理。無論是客戶端發送消息到服務還是服務返回消息給客戶端,都是如此。當客戶端調用服務時,只要接收到完整的消息,服務就會被調用,當包含了調用結果的返回消息被客戶端完整接收時,才會接觸對客戶端的阻塞。對於數據量小的消息,這種交換模式提供了簡單的編程模型,因為接收消息的耗時較短,然而,一旦處理數據量更大的消息,例如包含了多媒體內容或大文件,如果每次都要等到完整地接收消息之后才能解除阻塞,這未免也不現實。為了解決這樣的問題,WCF允許接收端通過通道接收消息的同時,啟動對消息數據的處理,這樣的處理過程稱為流傳輸模型。對於具有大量負載的消息而言,流操作改善了系統的吞吐量和響應速度,因為在發生和接收消息的同時,不管是發送端還是接收端都不會被阻塞。
三、WCF中回調操作的實現
上面介紹了WCF中支持的四種操作,下面就具體看看WCF中回調操作的實現。該例子的基本原理是:客戶端調用服務操作,服務操作通過客戶端上下文實例調用客戶端操作。下面還是按照三個步驟來實現該WCF程序。
第一步:同樣是實現WCF服務契約和契約的實現。具體的實現代碼如下所示:
1 // 指定回調契約為ICallback 2 [ServiceContract(Namespace="http://cnblog.com/zhili/", CallbackContract=typeof(ICallback))] 3 public interface ICalculator 4 { 5 [OperationContract(IsOneWay = true)] 6 void Multiple(double a, double b); 7 } 8 9 // 回調契約的定義,此時回調契約不需要應用ServiceContractAttribute特性 10 public interface ICallback 11 { 12 [OperationContract(IsOneWay = true)] 13 void DisplayResult(double x, double y, double result); 14 } 15 16 // 服務契約的實現 17 public class CalculatorService : ICalculator 18 { 19 #region ICalculator Members 20 public void Multiple(double a, double b) 21 { 22 double result = a * b; 23 // 通過客戶端實例通道 24 ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>(); 25 26 // 對客戶端操作進行回調 27 callback.DisplayResult(a, b, result); 28 } 29 #endregion 30 }
第二步:實現服務宿主。這里還是以控制台程序作為服務宿主。具體的實現代碼如下所示:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 using (ServiceHost host = new ServiceHost(typeof(CalculatorService))) 6 { 7 host.Opened += delegate 8 { 9 Console.WriteLine("Service start now...."); 10 }; 11 12 host.Open(); 13 Console.Read(); 14 } 15 } 16 }
宿主對應的配置文件內容如下所示:
<configuration> <system.serviceModel> <behaviors> <serviceBehaviors> <behavior> <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:8080/Metadata"/> </behavior> </serviceBehaviors> </behaviors> <services> <service name="WCFContractAndService.CalculatorService"> <endpoint address="net.tcp://localhost:9003/CalculatorService" binding="netTcpBinding" contract="WCFContractAndService.ICalculator"/> </service> </services> </system.serviceModel> </configuration>
第三步:實現客戶端。由於服務端來對客戶端操作進行回調,所以此時客戶端需要實現回調契約。首先以管理員權限啟動服務宿主,服務宿主啟動成功之后,客戶端通過添加服務引用的方式來生成客戶端代理類,此時需要在添加服務引用窗口地址中輸入:http://localhost:8080/Metadata。添加服務引用成功之后,接着在客戶端實現回調契約,具體的實現代碼如下所示:
1 // 客戶端中對回調契約的實現 2 public class CallbackWCFService : ICalculatorCallback 3 { 4 public void DisplayResult(double a, double b, double result) 5 { 6 Console.WriteLine("{0} * {1} = {2}", a, b, result); 7 } 8 }
接下來就是實現測試回調操作的客戶端代碼了。具體的實現步驟是:實例化一個回調類的實例,然后把它作為上下文實例的操作,最后把上下文實例作為客戶端代理的參數來實例化客戶端代理。具體的實現代碼如下所示:
1 // 客戶端實現,測試回調操作 2 class Program 3 { 4 static void Main(string[] args) 5 { 6 InstanceContext instanceContex = new InstanceContext(new CallbackWCFService()); 7 CalculatorClient proxy = new CalculatorClient(instanceContex); 8 proxy.Multiple(2,3); 9 10 Console.Read(); 11 } 12 }
下面運行運行該程序來檢測下該程序是否能夠成功回調,首先以管理員權限啟動服務宿主程序,再啟動客戶端程序,如果回調成功,你將看到如下圖所示的運行結果:
這里只是演示了回調操作的實現,關於流操作的實現,這里就不再去實現了,等具體需要的時候再去研究吧,同時給出關於流操作實現的參考文章:
四、總結
到這里,WCF操作的內容就分享結束了,本文首先介紹了在WCF中支持四種操作:請求-應答操作、單向操作、回調操作和流操作,WCF中默認的操作時請求-應答操作,最后實現了一個回調操作的實例。
本文所有源碼:WCFCallbackOperation.zip