當發生一次WCF請求-響應操作時,會經過如下幾個步驟
-
WCF Client想WCF Server發送一個服務請求
-
WCF Server創建WCF服務對象
-
WCF Server調用WCF服務對象接口,將結果返回給WCF客戶端。
操作過程中就牽涉到了服務對象的創建,但由於WCF服務對象是WCF框架管理,一般的時候並不關注它何時創建,何時回收。對於無需訪問成員變量的狀態無關的服務來說,這個並不影響我們的功能實現。
但是,許多時候我們也需要提供與狀態相關的服務,這個時候需要通過服務對象的成員變量來保存狀態。此時,我們就需要關注WCF的服務對象的創建策略了。下面就以一個計數器為例,介紹一下不同的策略對服務結果的影響。
[ServiceContract]
public interface IService1
{
[OperationContract]
int Increment();
}
[ServiceBehavior]
public class Service1 : IService1
{
private int intCounter;
public int Increment()
{
intCounter++;
return intCounter;
}
}
一般來講,我們有如下三種策略創建WCF對象:
-
PerCall 每次WCF服務調用都創建一個新的WCF服務對象,
-
PerSession 每個WCF會話期間只創建一個WCF服務對象,如果沒有會話設置,則效果同PerCall(默認策略)
-
Single 所有WCF會話共享一個WCF服務對象
這三種策略可以ServiceBehavior在中通過InstanceContextMode顯式設置。
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Service1 : IService1
注意:由於如果會話沒有啟用的話的話,PerSession效果同PerCall,而默認的協議basicHttpBinding不支持會話,為了正確演示這個示例,請將協議綁定到wsHttpBinding。
PerCall模式:
在這種方式下,每次WCF服務調用都創建一個新的WCF服務對象,調用完請求后,該對象便進入可回收狀態。
在這種方式下,無論客戶端如何調用,由於每次都是創建新對象,則計數永遠都是1
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Service1 : IService1
{
}
PerSession模式
在這種模式下,每個會話對應一個服務對象,會話結束后服務對象被回收。也就是說:
-
同一個客戶端的所有調用都發送給同一個服務對象
-
不同的客戶端的調用發送給不同的服務對象
在這種方式下,每一個客戶端都是獨立計數的。
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class Service1 : IService1
{
}
Single模式
在這種模式下,所有會話都對應同一個服務對象。
這個方式下,所有的客戶端的計數都會被累加起來。
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class Service1 : IService1
{
}
服務對象生命周期和Dispose
雖然我們通過InstanceContextMode控制服務對象的生命周期,但是我們也無法得之服務對象何時釋放。一般情況下,這個確實無需關心,但是,如果服務對象中如果在成員變量中保存了資源,我們就得需要確保資源能夠及時釋放。
按照.net設計原則,如果成員中保存了資源,則需要實現IDisposable接口,然后再Dispose方法中釋放資源。實際上,在WCF中也是遵循這個規則的:對於實現了IDisposable接口的服務對象,在該對象生命周期結束后,就會調用其Dispose方法以確保及時釋放資源。也就是說,只要我們的實現符合基礎的設計准則,WCF框架自動及時釋放。
活用一下這個規則:我們可以利用Dispose方法感知會話模式下成員的下線。
三種方式的比較
從性能上來看,Single模式全局只創建一個對象,開銷最小。而PerCall每次調用都創建一個對象,看起來開銷最大,但是它的可擴展性是最好的,非常容易實現負載分擔,並且資源釋放最為及時。
從功能上來看,PerSession和面向對象的模式最為接近,實現各種復雜的邏輯更為容易。
