閱讀62 返回首頁    go 阿裏雲 go 技術社區[雲棲]


WCF後續之旅(9):通過WCF的雙向通信實現Session管理[上篇]

一、Session 管理提供的具體功能

  • Start/End Session:可以調用service開始一個新的Session或者結束掉一個現有的Session。當開始一個Session的時候,service根據client端傳入的client相關的信息(ClientInfo),創建一個SessionInfo對象,該對象由一個GUID類型的SessionID唯一標識,代表一個具體的Client和Service的Session。在service端,通過一個dictionary維護者一個當前所有的active session列表,key為SessionID,value是SessionInfo對象。當client調用相應的service,傳入對應的SessionID,該SessionID對應的SessionInfo從該session列表中移除。
  • Session Timeout:如同ASP.NET具有一個Timeout的時間一樣,我們的例子也具有timeout的機製。在client可以注冊timeout事件,某個session timeout,service會通過在start session中指定的callback回調相應的操作(OnTimeout)並處罰client注冊的timeout事件。session timeout後,SessionInfo對象從active session列表中移除。 比如在本例中,我們通過注冊事件使得timeout後,程序在顯示timeout message之後,自動退出。
  • Session Renew:session timeout判斷的依據是client最後活動的時間(last activity time),而該事件反映的是最後一次鼠標操作的時間(假設我們的client是一個GUI應用)。所以從session的生命管理來講,用戶的每次鼠標操作實際上將session的時間延長到session timeout的時間。
  • Session Listing Viewing:Administrator或者某個具有相應權限的用戶,可以查看當前活動的session列表和session相關的信息,比如IP地址、主機名稱、用戶名、session開始的時間和最後一次活動的時間,見下圖。
  • Session Killing:如何發現某個用戶正在做一些不該做的事情,或者發現當前的並發量太大,管理員可以強行殺掉某個正在活動的Session。同session timeout一樣,client端可以注冊session killed事件。當session被強行中止後,service回調client相應的方法(OnSessionKilled),觸發該事件。比如在本例中,我們通過注冊事件使得某個client對應的session被殺掉後,該client程序在顯示message之後,自動退出。

wcf_02_09_01_thumb1

二、Session Timeout的實現原理

1、客戶端驅動

image_thumb1

2、服務端驅動

System.Runtime.Remoting.Lifetime.ISponsor)引用lease對象. 當Lease Manager檢測到某個remote object的lease超時,Remoting不會馬上對其進行垃圾回收,而是找到該lease的Sponsor對象,通過Sponsor對象回調Renewal方法(Sponsor處於client端),返回一個Timespan對象,表明需要將remote object的lifetime延長的時間,如何該值小於或者等於零,則不需要延長,該對象將會被回收掉;否則將lifetime延長至相應的時間。同時,client的每次遠程調用,都會自動實現對lifetime的Renew功能。(詳細內容可以參考我的文章:[原創]我所理解的Remoting (2) :遠程對象的生命周期管理-Part II)

image_thumb3

步驟一

步驟二

步驟三

步驟四

步驟五

注:可能有人會說,為什麼不將LastActivityTime返回到service端,service將session的LastActivityTime設定成該值就可以了呀?實際上,這樣做依賴於這樣的一個假設:client端的時間和server端的時間是一致的。很顯然,我們不能作出這樣的假設。

三、整個應用的結構

wcf_02_09_02_thumb1

   1: namespace Artech.SessionManagement.Contract
   2: {
   3:     [DataContract]
   4:     public class SessionClientInfo
   5:     {
   6:         [DataMember]
   7:         public string IPAddress{ get; set; } 
   8:  
   9:         [DataMember]
  10:         public string HostName{ get; set; } 
  11:  
  12:         [DataMember]
  13:         public string UserName{ get; set; } 
  14:  
  15:         [DataMember]
  16:         public IDictionary<string, string> ExtendedProperties{ get; set; }
  17:     }
  18: } 

   1: namespace Artech.SessionManagement.Contract
   2: {
   3:     [DataContract]
   4:     [KnownType(typeof(SessionClientInfo))]
   5:     public class SessionInfo
   6:     {
   7:         [DataMember]
   8:         public Guid SessionID{ get; set; } 
   9:         [DataMember]
  10:         public DateTime StartTime{ get; set; } 
  11:         [DataMember]
  12:         public DateTime LastActivityTime{get;set;} 
  13:         [DataMember]
  14:         public SessionClientInfo ClientInfo{ get; set; } 
  15:         public bool IsTimeout{ get; set; }
  16:     }
  17: } 
  18:  

   1: namespace Artech.SessionManagement.Contract
   2: {    
   3:     public interface ISessionCallback
   4:     {
   5:         [OperationContract]
   6:         TimeSpan Renew(); 
   7:  
   8:         [OperationContract(IsOneWay = true)]
   9:         void OnSessionKilled(SessionInfo sessionInfo); 
  10:  
  11:         [OperationContract(IsOneWay = true)]
  12:         void OnSessionTimeout(SessionInfo sessionInfo);
  13:     }
  14: } 

   1: namespace Artech.SessionManagement.Contract
   2: {
   3:     [ServiceContract(CallbackContract = typeof(ISessionCallback))]
   4:     public interface ISessionManagement
   5:     {
   6:         [OperationContract]
   7:         Guid StartSession(SessionClientInfo clientInfo, out TimeSpan timeout); 
   8:  
   9:         [OperationContract]
  10:         void EndSession(Guid sessionID); 
  11:  
  12:         [OperationContract]
  13:         IList<SessionInfo> GetActiveSessions(); 
  14:  
  15:         [OperationContract]
  16:         void KillSessions(IList<Guid> sessionIDs);
  17:     }
  18: }

具體實現請參閱Part II.

 

 WCF後續之旅: 

WCF後續之旅(1): WCF是如何通過Binding進行通信的 
WCF後續之旅(2): 如何對Channel Layer進行擴展——創建自定義Channel 
WCF後續之旅(3): WCF Service Mode Layer 的中樞—Dispatcher 
WCF後續之旅(4):WCF Extension Point 概覽 
WCF後續之旅(5): 通過WCF Extension實現Localization 
WCF後續之旅(6): 通過WCF Extension實現Context信息的傳遞 
WCF後續之旅(7):通過WCF Extension實現和Enterprise Library Unity Container的集成 
WCF後續之旅(8):通過WCF Extension 實現與MS Enterprise Library Policy Injection Application Block 的集成 
WCF後續之旅(9):通過WCF的雙向通信實現Session管理[Part I] 
WCF後續之旅(9): 通過WCF雙向通信實現Session管理[Part II] 
WCF後續之旅(10): 通過WCF Extension實現以對象池的方式創建Service Instance 
WCF後續之旅(11): 關於並發、回調的線程關聯性(Thread Affinity) 
WCF後續之旅(12): 線程關聯性(Thread Affinity)對WCF並發訪問的影響 
WCF後續之旅(13): 創建一個簡單的WCF SOAP Message攔截、轉發工具[上篇] 
WCF後續之旅(13):創建一個簡單的SOAP Message攔截、轉發工具[下篇] 
WCF後續之旅(14):TCP端口共享 
WCF後續之旅(15): 邏輯地址和物理地址 
WCF後續之旅(16): 消息是如何分發到Endpoint的--消息篩選(Message Filter) 
WCF後續之旅(17):通過tcpTracer進行消息的路由


作者:蔣金楠
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
原文鏈接

最後更新:2017-10-30 17:04:42

  上一篇:go  一個通過BackgroundWorker實現WinForm異步操作的例子
  下一篇:go  WCF後續之旅(9): 通過WCF雙向通信實現Session管理[下篇]