理解WCF中的會話機制
- 在WCF應用程序中,會話將一組消息相互關聯,從而形成對話。會話”是在兩個終結點之間發送的所有消息的一種相互關系。當某個服務協定指定它需要會話時,該協定會指定所有調用(即,支持調用的基礎消息交換)必須是同一對話的一部分。如果某個協定指定它允許使用會話但不要求使用會話,則客戶端可以進行連接,並選擇建立會話或不建立會話。如果會話結束,然后在同一個通道上發送消息,將會引發異常。
- WCF中的會話機制通過設置服務協定(ServiceContract)上的SessionMode的枚舉值來設置服務協定是否要求、允許或拒絕基於會話的綁定。SessionMode的枚舉值有以下三種:
- Allowed:允許會話,這是SessionMode的默認值。也就是說在服務協定上沒有采用SessionMode說明時,我們的服務都是采用的允許會話機制。這種機制說明如果客戶端將基於會話的綁定用於 WCF 服務實現,則服務將建立並使用提供的會話。
- Required:要求會話,即所有調用(支持調用的基礎消息交換)都必須是同一個會話的一部分。
- NotAllowed:禁止會話,即服務端不會與客戶端進行消息交換。
影響WCF中的會話機制其他屬性機制
- 雖然可以設置SessionMode的值來控制會話,但是基於會話的綁定支持服務對象與特定會話的默認關聯,例如:
- 設置了SessionMode的值為Required,當采用的綁定為BasicHttpBinding,因為BasicHttpBinding不支持會話,所以程序還是報錯。
- 對於WSHttpBinding和WS2007HttpBinding,如果我們將安全模式設置為None(關閉安全會話)並且關閉可靠會話,他們也無法提供會話支持。
- 對於NetTcpBinding和NetNamedPipeBinding來說,由於其傳輸類型本身具有支持會話的特性,所以采用了這兩種綁定類型的終結點服務協定的會話模式不能設置為NotAllowed,即使關閉了安全會話和可靠會話也不行。
- WCF 提供下列類型的基於會話的應用程序行為:
- System.ServiceModel.Channels.SecurityBindingElement 支持基於安全的會話,其中,兩個通信端采用統一的安全對話。例如:System.ServiceModel.WSHttpBinding 綁定(包含對安全會話和可靠會話的支持)默認情況下只使用對消息進行加密和數字簽名的安全會話。
- System.ServiceModel.NetTcpBinding 綁定支持基於 TCP/IP 的會話,以確保所有消息都由套接字級別的連接進行關聯。
- System.ServiceModel.Channels.ReliableSessionBindingElement 元素實現 WS-ReliableMessaging 規范,並提供對可靠會話的支持。在可靠會話中,可以配置消息以按順序傳遞並且只傳遞一次,從而使消息在對話期間即使經過多個節點也可以確保保密性。
- System.ServiceModel.NetMsmqBinding 綁定提供 MSMQ 數據報會話
- 如果使用 WCF 中的默認實例化行為,則通過同一服務實例來處理 WCF 客戶端對象之間的所有調用。因此,在應用程序級別上,可以將會話視為啟用與本地調用行為相似的應用程序行為。只要使用默認的服務實例行為,會話就會在客戶端和服務之間啟用一個相似的行為。如果服務協定需要或支持會話,則通過設置 IsInitiating 和 IsTerminating 屬性,可以將一個或多個協定操作標記為啟動或終止會話。參考WCF初探-15:WCF操作協定
WCF中的會話與ASP.NET中的會話
- WCF 會話具有下列主要概念性功能:
- 它們由調用應用程序顯式啟動和終止。
- 會話期間傳遞的消息按照接收消息的順序進行處理。
- 會話將一組消息相互關聯,從而形成對話。該關聯的含義是抽象的。例如,一個基於會話的通道可能會根據共享網絡連接來關聯消息,而另一個基於會話的通道可能會根據消息正文中的共享標記來關聯消息。可以從會話派生的功能取決於關聯的性質。
- 不存在與 WCF 會話相關聯的常規數據存儲區。
- ASP.NET 中的會話由 System.Web.SessionState.HttpSessionState 類提供功能,具有以下特點:
- ASP.NET 會話總是由服務器啟動。
- ASP.NET 會話原本是無序的。
- ASP.NET 會話提供了一種跨請求的常規數據存儲機制。
WCF中的使用會話示例說明
- 解決方案如下:
- 工程結構說明如下:
- Service:類庫程序,WCF服務端應用程序。服務協定中我們將SessionMode的值設置為Required,也就是服務必須要求會話。操作協定中將MethodOne的IsTerminating設置為true,也就是說在客戶端調用MethodOne后就會關閉會話(注意:設置了IsTerminating為true的方法是在調用后,服務的會話才會關閉,所以操作協定MethodOne在客戶端的調用是成功的)。ISampleMethod.cs的代碼如下:
using System.ServiceModel; namespace Service { [ServiceContract(SessionMode=SessionMode.Required)] public interface ISampleMethod { [OperationContract(IsTerminating=true)] string MethodOne(string msg); [OperationContract] string MethodTwo(string msg); } }
SampleMethod.cs的代碼如下:
namespace Service { public class SampleMethod:ISampleMethod { public string MethodOne(string msg) { return "You called MethodOne return message is: " + msg; } public string MethodTwo(string msg) { return "You called MethodTwo return message is: " + msg; } } }
2. Host:控制台應用程序,服務承載程序。添加對程序集Service的引用,完成以下代碼,寄宿服務。Program.cs代碼如下:

using System; using System.ServiceModel; using Service; namespace Host { class Program { static void Main(string[] args) { using (ServiceHost host = new ServiceHost(typeof(SampleMethod))) { host.Opened += delegate { Console.WriteLine("服務已經啟動,按任意鍵終止!"); }; host.Open(); Console.Read(); } } } }
App.config代碼如下:

<?xml version="1.0"?> <configuration> <system.serviceModel> <services> <service name="Service.SampleMethod" behaviorConfiguration="mexBehavior"> <host> <baseAddresses> <add baseAddress="http://localhost:1234/SampleMethod/"/> </baseAddresses> </host> <endpoint address="" binding="wsHttpBinding" contract="Service.ISampleMethod" /> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="mexBehavior"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="true"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
我們通過svcutil.exe工具生成客戶端代理類和客戶端的配置文件
svcutil.exe是一個命令行工具,位於路徑C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin下,
我們可以通過命令行運行該工具生成客戶端代理類
在運行中輸入cmd打開命令行,輸入 cd C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin
輸入svcutil.exe /out:f:\ SampleMethodClient.cs /config:f:\App.config http://localhost:1234/SampleMethod
3. Client:控制台應用程序,客戶端調用程序。將生成的SampleMethodClient.cs和App.config復制到Client的工程目錄下,完成客戶端調用代碼。
為驗證WCF的會話特點,我們將客戶端的調用分為以下幾種情況:
- 實例化客戶端代理類對象Client1,調用MethodOne和MethodTwo,由於MethodOne的IsTerminating設置為true,所以在客戶端Client1調用完MethodOne后會話就會關閉,所以MethodTwo調用不會成功。Client1在調用MethodOne的時候,會話機制會自動啟動。由於話期間傳遞的消息按照接收消息的順序進行處理,所以在Client1調用MethodOne后再次調用MethodOne也不會成功。即在調用MethodOne方法后的調用都不會成功。參考代碼如下:
using System; namespace Client{ class Program{ static void Main(string[] args){ try{ SampleMethodClient client1 = new SampleMethodClient(); Console.WriteLine(client1.MethodOne("MethodOne")); Console.WriteLine(client1.MethodTwo("MethodTwo")); }
catch (Exception ex){ Console.WriteLine(ex.Message); } finally{ Console.Read(); } }}}
運行結果如下:
- 實例化客戶端代理類對象Client1和Client2,在兩個實例化對象中分別調用MethodOne,可以看到調用成功,因為默認的服務實例化模型(InstanceContextMode)采用PerSession,即每個服務實例都各自創建了一個會話通道,當Client1調用MethodOne后會話關閉,但Client2的會話通道並沒有關閉,所以還是可以調用MethodOne。在調用MethodOne后兩個會話都會關閉,這是由於MethodOne的IsTerminating設置為true的結果。參考代碼如下:
try { SampleMethodClient client1 = new SampleMethodClient(); Console.WriteLine(client1.MethodOne("First Called MethodOne")); SampleMethodClient client2 = new SampleMethodClient(); Console.WriteLine(client2.MethodOne("Second Called MethodOne")); } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { Console.Read(); }
運行結果如下:
- 由於本示例采用的是wsHttpBinding綁定機制,可以把客戶端生成的配置文件的可靠會話(reliableSession) enabled設置為false,安全會話(security)的mode設置為none.這樣即使服務協定采用了會話支持,但是由於綁定機制的影響,所以會話通道不會建立成功。將客戶端配置文件中的
<security mode="Message"> <transport clientCredentialType="Windows" proxyCredentialType="None" realm="" /> <message clientCredentialType="Windows" negotiateServiceCredential="true" algorithmSuite="Default" establishSecurityContext="true" /> </security>
替換為
<security mode="None"/>
運行結果如下: