理解WCF中的實例化機制
- “實例化”是指對用戶定義的服務對象以及與其相關的 InstanceContext 對象的生存期的控制。也就是說我們的客戶端程序在調用服務端方法時,需要實例化一個服務端代理類對象,實例化就是對這個對象的生命周期的管理(比如:代理服務對象的創建,對象調用服務端方法后需要對其進行的回收處理)。
- 實例化行為(使用 System.ServiceModel.ServiceBehaviorAttribute.InstanceContextMode 屬性進行設置)控制如何創建 InstanceContext 以響應傳入的消息。默認情況下,每個 InstanceContext 都與一個用戶定義服務對象相關聯,因此設置 InstanceContextMode 屬性也可以控制用戶定義服務對象的實例化。InstanceContextMode 枚舉定義了實例化模式。可以使用下列實例化模式:
- PerCall:單調模式,為每個客戶端請求創建一個新的 InstanceContext(以及相應的服務對象)。
- PerSession:會話模式,這是InstanceContextMode的默認值,為每個新的客戶端會話創建一個新的 InstanceContext(以及相應的服務對象),並在該會話的生存期內對其進行維護(這需要使用支持會話的綁定)。
- Single:單例模式,單個 InstanceContext(以及相應的服務對象)處理應用程序生存期內的所有客戶端請求。
單調模式(PerCall)下的服務實例
- 在單調模式(PerCall)中,WCF總是創建一個新的服務實例上下文來處理請求對象,即調用一次方法就會創建一個實例上下文對象,調用完成后依靠GC機制釋放對象(可能會有延遲),再調用下一個方法時也會創建一個新的服務實例上下文對象。因此,在一個服務通道會話中可能出現多個實例上下文對象
- 接下來我將通過示例來驗證單調模式下的實例處理請求的方式。解決方案的創建請參照WCF初探-26:WCF中的會話,此示例中,我們采用GetInstanceId()來獲取服務端實例化的次數,采用GetOperationCount()來獲取調用方法的計數器。ISampleMethod.cs的代碼如下:
using System.ServiceModel; namespace Service{ [ServiceContract(SessionMode=SessionMode.Required)] public interface ISampleMethod{ [OperationContract] string MethodOne(string msg); [OperationContract] string MethodTwo(string msg); [OperationContract] int GetInstanceId(); //獲取服務實例ID [OperationContract] int GetOperationCount(); //獲取調用操作方法的計數器 }}
SampleMethod.cs的代碼如下:
using System.ServiceModel; namespace Service{ [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] public class SampleMethod:ISampleMethod { static int instanceCount; int instanceId; int operationCount; public SampleMethod() { instanceCount++; instanceId = instanceCount; } public string MethodOne(string msg) { operationCount++; return "You called MethodOne return message is: " + msg; } public string MethodTwo(string msg) { operationCount++; return "You called MethodTwo return message is: " + msg; } public int GetInstanceId() { return instanceId; } public int GetOperationCount() { return operationCount; } } }
寄宿服務后,使用svcutil.exe生成客戶端代理類和配置文件,客戶端參考代碼如下:
class Program{ static void Main(string[] args){ SampleMethodClient client1 = new SampleMethodClient(); CallMethod(client1); SampleMethodClient client2 = new SampleMethodClient(); CallMethod(client2); Console.Read(); } static void CallMethod(SampleMethodClient client){ Console.WriteLine(client.MethodOne("MethodOne")); Console.WriteLine("InstanceId:{0},OperationCount:{1}", client.GetInstanceId(), client.GetOperationCount()); Console.WriteLine(client.MethodTwo("MethodTwo")); Console.WriteLine("InstanceId:{0},OperationCount:{1}", client.GetInstanceId(), client.GetOperationCount()); } }
運行結果如下:
- 運行結果說明如下:
- Client1調用MethodOne()時,會進入到SampleMethod構造函數此時instanceCount會加1,所以instanceId等於1,operationCount加1后的值為1.
- Client1調用GetInstanceId()時,會再次進入SampleMethod構造函數產生新的實例,由於instanceCount為靜態變量,所以再次加1后會變成2,所以instanceId等於2。operationCount的普通變量,所以實例化后不會記錄先前的值,調用GetOperationCount()時operationCount沒有加量操作。所以為默認值0.調用GetOperationCount()后instanceId的值等於3.
- Client1調用MethodTwo()時,又會進入到SampleMethod構造函數產生新的實例,所以instanceId的值就會等於4.再次調用GetInstanceId()時,新的實例值又會增加1,所以客戶端最終會輸出5.而調用的操作計數器始終為0.
- 其實就是客戶端每做一次調用操作,SampleMethod就會被實例化一次,由此我們可以查看到instanceId和OperationCount值的變化。
單例模式(Single)下的服務實例
- 在單調模式(single)中,WCF只會創建一個實例上下文來處理服務的所有請求調用對象,即 SampleMethod只會進行一次實例化。不管調用的請求對象是在同一個客戶端還是在不同的客戶端。
- 要檢驗單調模式(single),我們只需把服務行為的InstanceContextMode設置為single,重新編譯工程后,運行結果如下:
- 運行結果說明:由於WCF采用單例模式只會生成一個實例化上下文,所以從運行的結果可以看到instanceId的值始終為1,而操作計數器OperationCount也在不斷做累加,再經過Client1和Client2調用處理后,在MethodOne()和MethodTwo()做累加,所以最終的值為4.
會話模式(PerSession)下的服務實例
- 在會話模式(PerSession)中,WCF會對客戶端與服務端的每一個會話通道創建一個實例上下文。即不同的客戶端在各自的會話通道的實例上下文中處理請求對象。
- 要檢驗會話模式(PerSession),我們只需把服務行為的InstanceContextMode設置為PerSession,重新編譯工程后,運行結果如下:
- 運行結果說明:從運行結果可以看出客戶端實例Client1的調用所在的instanceId為1,操作計數器OperationCount經過兩次的調用(調用MethodOne()和MethodTwo())后做累加,最后的值為2.客戶端Client2調用的時候會產生新的實例上下文。所以instanceId的值為2,操作計數器OperationCount又會重新開始計數。