老老實實學WCF
第七篇 會話
通過前幾篇的學習,我們已經掌握了WCF的最基本的編程模型,我們已經可以寫出完整的通信了。從這篇開始我們要深入地瞭解這個模型的高級特性,這些特性用來保證我們的程序運行的高效、穩定和安全。
首先我們來學習會話。
1. 什麼是會話
會話是通信雙方進行通信的一個時間片、一個語境或者說一個上下文,在這個特定的環境中,通信的雙方是彼此認識的,就像兩個人在聊天,他們都很清楚誰在聆聽自己講話,也很清楚對方講的話是給自己聽的,簡單的說就是通信雙方是可以記住彼此的。
一旦會話結束了,通信雙方就忘記了彼此,即使他們再次建立會話,他們也不會記得他們上次會話的內容,也就是他們不記得他們曾經見過面。
這在我們現實世界中或許很難想象,但是在通信的世界裏就是這樣的。服務端不可能記住每個跟他通信的人,他只能在一段時間內(會話)記住一個人。
這個特性是很有用的,有些邏輯需要客戶端和服務端通信多次才能完成,在這個期間雙方需要記住彼此,而且會話也是很多其他特性實現的基礎,例如雙工通信。
2. 如何建立會話
那麼我們要想建立一個會話通信,應該具備怎樣的條件呢?
(1) 需要支持會話的綁定。綁定描述了雙方的通信方式,不同的綁定對會話的支持是不同的,比如basicHttpBinding是不支持會話的,而wsHttpBinding就是支持的。要建立會話通信,這個通信必須首先使用支持會話的綁定。
(2) 讓服務協定支持會話,服務協定實際上就是通信的通道(見第四、五篇),讓服務協定支持會話,那麼就可以在這個通信通道上支持會話了。
選擇支持會話的綁定我們知道怎麼做,可如何讓服務協定支持會話呢?要用到在修飾服務協定的SeviceContract屬性,我們知道被這個屬性修飾的接口是一個服務協定,其實這個屬性也擁有屬性,其中一個屬性叫做SessionMode。這是一個枚舉,我們通過設置這個枚舉的值來配置服務協定是否支持會話。例如:
[ServiceContract(SessionMode = SessionMode.Required)] public interface IHelloWCF { [OperationContract] string HelloWCF(); }
這段代碼中,我把SessionMode設置爲了Required,這表示調用這個服務協定的客戶端必須使用會話。
SessionMode有三個可能的值:
1) Allowed:這是默認值,表示這個服務協定是允許會話的,客戶端可以選擇用會話連接,也可以選擇不用會話連接。
2) Required:表示服務協定要求客戶端連接必須使用會話。
3) NotAllowed:表示服務協定不允許使用會話連接。
這些配置需要搭配其他的配置才能起到實際意義,比如服務實例模式,服務端和客戶端調用模式等等,等我們瞭解到這些特性的時候再展開,現在我們只需要知道,前兩種配置是支持會話的,第三種是不支持的。
3. 一個簡單的例子
我們通過一個簡單的例子來看看允許會話與不允許的區別,我修改了前幾篇中寄存在IIS中的服務,代碼如下:
using System; using System.ServiceModel; namespace LearnWCF { [ServiceContract(SessionMode = SessionMode.Allowed)] public interface IHelloWCF { [OperationContract] string HelloWCF(); } public class HelloWCFService : IHelloWCF { private int _Counter; public string HelloWCF() { _Counter++; return "Hello, you called " + _Counter.ToString() + " time(s)"; } } }
首先我們把服務協定的會話模式設置爲允許會話(Allowed),在服務實現中,我爲服務實現類定義了一個計數器成員,每次調用都會將這個計數器加一,然後返回一句話告訴客戶端調用了多少次。
服務端的配置文件如下:
<configuration> <system.serviceModel> <services> <service name="LearnWCF.HelloWCFService" behaviorConfiguration="metadataExchange"> <endpoint address="" binding="wsHttpBinding" contract="LearnWCF.IHelloWCF"/> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="metadataExchange"> <serviceMetadata httpGetEnabled="true" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
在這裏我配置了支持會話的wsHttpBinding。
客戶端的調用代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { ConsoleApplication2.ServiceReference1.HelloWCFClient client = new ServiceReference1.HelloWCFClient(); Console.WriteLine(client.HelloWCF()); Console.WriteLine(client.HelloWCF()); client.Close(); Console.Read(); } } }
就是連續調用兩次服務端的方法並輸出結果。
F5運行一下,會看到下面的結果:
我們看到提示調用了兩次,也就是說服務端記住了客戶端,當他第二次調用的時候將將計數器加一,就返回了調用兩次。當然這個局面的形成還受到實例上下文模式爲PerSession的影響,我們後面會展開,總之服務協定支持會話,纔出現了這個局面。
如果我們把SessionMode改成NotAllowed,其他不改動,結果就會是下面的樣子:
結果兩次都是1,說明服務器在第二次受到調用的時候已經忘記了之前那個客戶端,他又分配了一個新的計數器給這個客戶端,所以計數就總是1了。
其實這個例子是很粗糙的,這裏面還有些其他的影響因素,我們就是通過這個例子來看看SessionMode的一方面影響。
4. 總結
這一篇的內容比較少,我們應該記住一些要點,在以後接觸更多特性的時候纔不會混淆。
(1) 是否支持會話首先取決於選擇的綁定。
(2) 是否支持會話通過配置服務協定的ServiceContract屬性的SessionMode屬性實現的。