WCF足跡3:實例

WCF服務端需要處理大量客戶端的請求,每個客戶端可能要與一個或多個服務實例進和交互,這種交互模式有很多種,這也就決定了服務器端對實例的管理不能搞“一刀切”,需要具有有效的實例的管理功能。
WCF服務支持三種實例管理模式:
per-call:針對客戶端的每個請求創建一個新的服務實例。
sessionful:針對每個連接的客戶端創建一個服務實例。
singleton:所有的客戶端共享一個服務實例。


一、Per-Call服務:
在服務被配置成Per-Call實例模式的狀態時,客戶端代理每次對服務契約調用,WCF都會產生一個新服務實例來處理客戶請求,當處理完請求後,WCF就會把服務實例作爲一個垃圾,等待垃圾回收器來清理。
即使同一個客戶端先後兩次調用服務契約,WCF也會產生兩個不同的服務實例來處理客戶端請求。



《圖0》
特點:
1.服務實例在方法被調用時創建,調用完立即釋放
2.吞吐量大,內存開銷少。能有效節約服務器內存,也不會過長時間佔用昂貴的服務器資源(數據庫連接,文件指針等)。
3.不會產生併發問題
4.兩次調用之間不會保存狀態

代碼實現:
[ServiceContract]
public interface IPerCall
{
    [OperationContract]
    int Add();
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
public class PerCall : IPerCall
{
    private int _Count = 0;
    public int Add()
    {
        _Count++;
        return _Count;
    }
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]特性只能應用到類上。
上面的代碼中,是PerCall調用模式,每次調用PerCall類的Add()方法時,都會生成PerCall類的新對象,並把其_Count成員初始化爲0,然後再調用Add()方法中的代碼,把_Count成員變量自增1。所以每次調用Add()方法完成後,返回結果應當總是1。
使用“WCF測試客戶端”我們可以運行Add()方法,點擊“調用”發現每次返回的結果都是1。



《圖1》

二、Sessionful服務:
當服務的實例模式指定爲Sessionful時,每個客戶端代理會取得一個獨享的服務實例,並進行一對一的調用,這個服務實例不會在一次調用後立即釋放,而會一直存在,直到客戶端代理關閉(當客戶端代理關閉時會通知服務會話結束)。這種模式有點像傳統的C/S模式。
特點:
1.需要在服務器端管理實例狀態
2.吞吐量下降
3.服務器資源開銷過多
4.事務控制麻煩等問題。
5.一般來說,它只能爲幾十個客戶端進行服務。

注:如果客戶端啓用另一個代理請求服務,那會在服務端產生一個新的獨享服務實例來與之交互。

代碼實現:
[DataContract]
public class CallingResult
{
    private string _SessionID;
    [DataMember]
    public string SessionID
    {
        get { return _SessionID; }
        set { _SessionID = value; }
    }
    private int _Value;
    [DataMember]
    public int Value
    {
        get { return _Value; }
        set { _Value = value; }
    }
}

[ServiceContract]
public interface IPerSession
{
    [OperationContract]
    CallingResult Add();
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
public class PerSession : IPerSession
{
    private CallingResult _result;
    public PerSession()
    {
        _result = new CallingResult();
        _result.SessionID = OperationContext.Current.SessionId;
        _result.Value = 0;
    }
    public CallingResult Add()
    {
        _result.Value++;
        return _result;
    }
}
運行結果:



《圖3》

上面的[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]聲明指示PerSession服務的實例管理模式是PerSession模式,但並不是只要加上此聲明就可以在服務器上保存實例狀態。要在服務器上保留服務實例,並維持服務實例與客戶端的一一對應關係,那需要WCF能夠識別出不同的客戶端,然後才能把特定客戶端對應到特定的服務實例上去。並不是所有的綁定信道都能夠識別出不同客戶端的。
1.NetTcpBinding和NetNamedPipeBinding兩種綁定能夠在客戶端和服務端保持一個持續的連接,所以它們可以很好地把客戶端與服務實例關聯起來。可以使用PerSession實例模式
2.BasicHttpBinding綁定是通過Http協議進行數據傳輸的一種簡單的綁這下,而Http協議本身又是一種無狀態協議,所以服務端無法區分每次請求的客戶端。因此在這種綁定信道上是無法使用PerSession模式的。
3.WSHttpBinding綁定也是通過Http協議進行數據傳輸的,當然Http協議本身也是無狀態的,但它可以在消息頭中包含ID來識別不同的客戶端。因此,當WSHttpBinding在安全模式和可信賴消息模式下是可以使用PerSession模式的

雖然上面所說的NetTcpBinding、NetNamedPipeBinding和WSHttpBinding三種綁定信道可以使用PerSession模式,但需要讓客戶端知道該契約是否需要保持狀態,因此我們在定義服務契約的時候需要指明該契約的會話模式,這裏就用到了ServiceContract契約的SessionMode屬性:
public enum SessionMode
{
   Allowed,
   Required,
   NotAllowed
}
[AttributeUsage(AttributeTargets.Interface|AttributeTargets.Class,Inherited=false)]
public sealed class ServiceContractAttribute : Attribute
{
   public SessionMode SessionMode
   {get;set;}
   //More members
}
1.SessionMode.Allowed:這是SessionMode屬性的默認值。啓用傳輸會話,但應用程序不必須使用會話如果該服務行爲聲明爲PerCall,那它仍不會保留實例狀態。如果服務聲明爲PerSession,那它會根據信道情況確定是否保留實例狀態。
    BasicHttpBinding和WSHttpBinding兩種綁定並不支持傳輸會話,所以即使服務行爲被配置爲PerSession,那它依然採用PerCall的調用方式。
    NetTcpBinding、NetNamedPipeBinding和WSHttpBinding安全可信賴綁定支持傳輸會話,如果服務行爲被配置爲PerSession,那它採用PerSession調用方式。
   
2.SessionMode.Required:指定綁定信道必須支持傳輸會話如果綁定信道不支持傳輸會話,在加載服務的時候會產生異常。
    當服務行爲指定爲PerSession時,那此時服務端實例與客戶端代理可以實現一對一的調用,並能保存服務端實例的狀態。
    當服務行爲指定爲PerCall時,那此時仍不會在服務端保存實例狀態。
    如果要設計帶有會話狀態的服務契約的時候,建議把服務契約的SessionMode設爲SessionMode.Required。
   
3.SessionMode.NotAllowed:不啓用傳輸會話禁止服務保存服實例的狀態服務永遠是PerCall模式

綁定、契約和服務行爲的關係:
1.綁定指的是綁定信道:BasicHttpBinding、NetTcpBinding、NetNamedPipeBinding和WSHttpBinding等
2.契約指的是ServiceContract的SessionMode屬性:SessionMode.Allowed、SessionMode.Required、SessionMode.NotAllowed
3.服務行爲指的是ServiceBehavior的InstanceContextMode屬性:InstanceContextMode.PerCall、InstanceContextMode.PerSession、InstanceContextMode.Singleton
這三者的關係在需要保持會話狀態時(PerSession)關係很密切。而在PerCall和Singleton時並無太大關聯。



《圖4》
這裏舉個例子來說明這三個的關係:
隨着城市的規模越來越大,公共交通問題會越來越嚴重,假設一個城市A想要快速公交系統,那這個城市A必須要具備三個基本條件:路要好、車要快和合理的交通規則。
車速:相當於是否啓動程序會話。車速低相當於不啓用程序會話,車速高相當於啓用程序會話。
路:相當於綁定信道。地鐵,輕軌這二者自然是快速路,而普通的馬路則不行,一旦堵車就快不起來了,但如果在馬路上劃出公交專用通道,那公交的速度會大大加快,也可以作爲快速公交看待。
車:相當於服務行爲[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]。如果車太落後,行馳速度像馬車,那即使有了好的路不見得車就一定能快起來。也就是說雖然綁定信道支持傳輸會話,但服務行爲設爲PerCall那仍然是單一調模式。
交通規則:相當於契約中的傳輸會話的聲明[ServiceContract(SessionMode = SessionMode.Allow)]。如果有了好的路,有了好的車,但交通規則規定時速不得超過5公里,那照樣快不起來。也就是說綁定綁定信道支持傳輸會話,服務行爲也設爲PerSession,但就是契約的SessionMode設爲NotAllow,那照樣無法實現應用程序會話。反過來說,如果路面太差不支持快速公交的條件(綁定不支持傳輸會話),車又很好跑得很快(InstanceContextMode.PerSession),交通規則還要求車行速度不低於200碼(SessionMode=Required),那肯定會出異常

應用程序Session的維持時間默認爲10分鐘。可以在每個綁定上使用receiveTime指定Session時長。
<netTcpBinding>
   <binding name = "TCPSession">
      <reliableSession enabled = "true" inactivityTimeout = "00:00:05"/>
   </binding>
</netTcpBinding>



《圖7》

三、Singleton服務
Singleton模式是終極服務共享模式,所以客戶端共享一個服務實例,不管你是採用什麼樣的綁定信道。服務實例在宿主程序運行的時候創建,在宿主程序結束的時候釋放,中間全程佔用服務器資源。



《圖5》
特點:
1.所有客戶端調用同一實例
2.吞吐量受影響
3.對象在內存中佔用時間較長
4.容易產生併發性問題

代碼:
[DataContract]
public class CallingResult
{
    private string _SessionID;
    [DataMember]
    public string SessionID
    {
        get { return _SessionID; }
        set { _SessionID = value; }
    }
    private int _Value;
    [DataMember]
    public int Value
    {
        get { return _Value; }
        set { _Value = value; }
    }
}

[ServiceContract]
public interface IPerCall
{
    [OperationContract]
    CallingResult Add();
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class PerCall : IPerCall
{
    private CallingResult _result;
    public PerCall()
    {
        _result = new CallingResult();
        _result.SessionID = Guid.NewGuid().ToString();
        _result.Value = 0;
    }
    public CallingResult Add()
    {
        _result.Value++;
        return _result;
    }
}

啓運兩個WCF測試客戶端,運行效果如下:



《圖6》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章