我們在使用ASP.NET開發(fā)的過程中,有時會進行數(shù)據(jù)存儲以實現(xiàn)請求前后的狀態(tài)保持(HTTP是無狀態(tài)保持的協(xié)議),而Session作為一種快速簡單易于實現(xiàn)的方式被我們經(jīng)常使用,當然如果出于性能方面的考量,我們還是不建議往Seesion中塞入更多的東西,最好是不用Session。
還有一點需要說明的是,Session實現(xiàn)的本質是在客戶端產生一個SessionId,具體的數(shù)據(jù)存儲在服務器端,客戶端通過SessionId來獲取服務器端的具體數(shù)據(jù),那這個SeesionId是怎么保存在客戶端以及又是以什么方式來傳給服務器的呢?服務器端又是以什么方式保存Session的這些數(shù)據(jù)的呢?各種方式的優(yōu)缺點又是什么?這就是本篇隨筆想要記錄的內容。
二、配置方式上面是Session在Web.config的配置方式,下面對各個節(jié)點做一些簡單的介紹
mode(設置將服務器的Session信息存儲到哪里)
cookieless(設置客戶端的Session信息存儲到哪里)
從上面的設置配置中我們也可以發(fā)現(xiàn)Session和Cookie的關系:
Session過期時間設置,默認為20分鐘。
stateConnectionString
如果設置將Session信息存儲在State Server中時,則需要此配置字符串表明服務器名稱和端口。
sqlConnectionString
如果設置將Session信息存儲在SQL Server中,需此配置,表明數(shù)據(jù)庫的連接字符串,同時stateNetworkTimeout表明經(jīng)過多少秒空閑后,斷開Web服務器與存儲狀態(tài)信息的服務器的TCP/IP連接的。默認值是10秒鐘。
三、Session服務器端配置
1. InProc顧名思義,此種模式表示Session將會被保存在內存中,確切地說是保存在工作者進程中,對于IIS 5而言是aspnet_wp.exe,對于IIS 6而言是w3wp.exe,設置方式如下(Web.config)
由于是直接保存在進程中,所以性能最好,但是經(jīng)常會發(fā)生Session信息丟失,常見的導致進程重啟的可能情況為:
2. State Server
此種方式是將Session信息存儲在其它的進程中而不是IIS中,這樣就可以避免因IIS進程崩潰或重啟而導致的Session信息丟失。但是此種方式要求保存在Session的信息必須序列化,然后從Session中獲取的時候也要反序列化,這就導致性能有略微的損失。
StateServer是本機的一個服務,可以在系統(tǒng)服務里看到服務名為ASP.NET State Service的服務,默認情況是不啟動的。當我們設定mode為StateServer之后,請把該服務的啟動模式設置為自動(這樣下次服務就可以隨機器而啟動)并手工將該服務啟動運行。這樣,我們就能利用本機的StateService來存儲Session了,除非電腦重啟或者StateService崩掉,否則Session是不會丟的。
此種配置和上面是一樣的(多了個stateConnectionString,換句話說127.0.0.1是默認本機IP,42424默認是該服務的訪問端口號,寫不寫效果是一樣的),都表示StateServer是在本機(注:StateServer模式是支持遠程主機服務的,配置類似與下面)
注:如果在啟動ASP.NET State Service服務時遇到問題0x8007277a 即無法啟動或初始化,請嘗試在命令行(CMD)中輸入netsh winsock reset(有可能是winsock的問題,所以需reset一下)
3. SQL Server
此種方式是把Session信息保存在SQL Server的數(shù)據(jù)庫中,也需要序列化,性能有較大損失,但是Session一般不會發(fā)生丟失的情況,除非SQL Server宕機。而且此種方式也可以實現(xiàn)在Web Farm中的Session信息共享(上面兩種方式都不可以)。
3.1 安裝ASPState數(shù)據(jù)庫
在使用之前,我們要安裝配置對應的數(shù)據(jù)庫,而微軟給我們提供了一整套方案(你也可以選擇使用自己的數(shù)據(jù)庫或自己實現(xiàn)配置和管理)。ASP.NET 2.0版本后微軟提供了aspnet_regsql.exe工具可以方便的配置Session數(shù)據(jù)庫,該工具位于 Web 服務器上的'系統(tǒng)根目錄\Microsoft.NET\Framework\版本號'文件夾中.
使用舉例:aspnet_regsql.exe -S . -U session_user -P Session@Pwd -ssadd -sstype p
-S參數(shù):表示數(shù)據(jù)庫實例名稱. 可以用'.'表示本機,你也可以指定機器,如10.7.11.110等
-U和-P參數(shù):表示用戶名和密碼.
-E參數(shù):可以再-U –P 與 -E中選擇一組. –E表示以當前系統(tǒng)用戶通過windows身份驗證登錄數(shù)據(jù)庫, -U -P則是使用SqlServer用戶登錄數(shù)據(jù)庫.
-ssadd / –ssremove 參數(shù):
-ssadd表示是添加Session數(shù)據(jù)庫, -ssremove表示移除Session數(shù)據(jù)庫.
sstype 參數(shù):將會話數(shù)據(jù)存儲到 SQL Server tempdb 數(shù)據(jù)庫中。這是默認設置。如果將會話數(shù)據(jù)存儲到 tempdb 數(shù)據(jù)庫中,則在重新啟動 SQL Server 時將丟失會話數(shù)據(jù)。
將會話數(shù)據(jù)存儲到 ASPState 數(shù)據(jù)庫中,而不是存儲到 tempdb 數(shù)據(jù)庫中。
將會話數(shù)據(jù)存儲到自定義數(shù)據(jù)庫中。如果指定 c 選項,則還必須使用 -d 選項包括自定義數(shù)據(jù)庫的名稱。
注意:如果sstype為t,則在下面的用戶權限賦予中要授予對tempdb的dbowner權限,否則將無法操作數(shù)據(jù)庫。
3.2 建立連接數(shù)據(jù)庫 ASPState 的用戶,并為此用戶授權
運行 SQL Server 的企業(yè)管理器 展開數(shù)據(jù)庫的安全性 右擊'登錄' 新建'登錄' 輸入'名稱' 選擇 'SQL Server 身份驗證' 輸入'密碼' 指定'數(shù)據(jù)庫' 點擊'數(shù)據(jù)庫訪問' 勾選 'ASPState' 選中'db_owner'角色 點擊'確定' 再一次輸入'密碼' 點擊'確定' 后即可建立 ASPState 的用戶,下面用命令實現(xiàn):
--新建數(shù)據(jù)庫賬號 SessionStateUser ,默認登錄 ASPState
EXEC sp_addlogin 'SessionStateUser', '123456', 'ASPState'
use ASPState --切換 DataBase
--將 SessionStateUser 授予 db_owner 的權限
exec sp_adduser 'SessionStateUser', 'SessionUser' ,'db_owner'
3.3 啟動SQL Server Agent
自動運行Job ASPState_Job_DeleteExpiredSessions刪除過期的Session,否則數(shù)據(jù)庫中的數(shù)據(jù)將一直增長。
四、Session客戶端配置
再次說明,Session的實現(xiàn)分為兩個部分:客戶端和服務器端,其中客戶端負責產生SessionId,服務器端負責保存具體的內容,這兒所說的Session客戶端配置其實是想說說關于SessionId的一些東西。
1. Session在客戶端是如何實現(xiàn)的?
前面已經(jīng)說過,Session在客戶端是通過產生SessionId來實現(xiàn)的,至于這個SessionId又是通過什么方式回傳之服務器從而獲得具體的Session內容,前面也略有說明,兩種方式:Cookie和Url,由于Url的方式會導致安全性問題,所以現(xiàn)在一般已不再使用此種方式。
當系統(tǒng)是用Session的時候,系統(tǒng)將自動在客戶端產生一個Cookie,名稱為ASP.NET_SessionId,為了便于區(qū)別,我們暫且將此Cookie稱為Session Cookie
2. Session Cookie何時失效?
和一般的Cookie一樣,默認是保存在瀏覽器的內存中,當瀏覽器關閉時失效,如果想此Cookie保存在本地磁盤,可通過設置其Expires屬性來達到,這種方式現(xiàn)在也被廣泛應用于網(wǎng)站的登錄,即用戶在登錄的時候選擇記住我或保持登錄一段時間,這樣當用戶下次再次訪問的時候就無需再次輸入用戶名密碼從而達到快速訪問的目的
3. Session Cookie失效時Session失效嗎?
答案當然是否定的,記?。篠ession Cookie和Session的失效沒有任何必然的聯(lián)系,因為它們失效的基準或者條件根本不一樣,Session Cookie的失效時間取決于客服端Cookie的失效時間,如果是保存在瀏覽器中,那么關閉瀏覽器Session Cookie就將失效,否則如果保存在本地磁盤,則取決于該Session Cookie設置的過期時間;而服務器端的Session是保存在服務器端的,它的失效與否與其服務器端的設置和Session的過期時間有關(下面的討論將忽略過期時間這個因數(shù),你懂的),如果是InProc方式,那么當承載的IIS進程如果奔潰或重啟等都會丟失;如果是State Server,同樣如果這個Service宕掉,那Session也會丟失;而如果是SQL Server,則會寫入數(shù)據(jù)庫,如果你不刪除它,它甚至可以一直存在而永不丟失(事實是SQL Server Agent會自動運行一個Job刪除過期的Session);而當如果我們使用自定義的數(shù)據(jù)庫來保存Session時,你將獲得充分的控制。
4. Session Cookie何時產生?刷新頁面其值會改變嗎?
牢記一點,只有當使用Session的時候才會產生Session Cookie。你也許會反問那為什么當配置Session模式為SQLServer時,就算沒有使用Session,也可以獲得ASP.NET_SessionId的值,即在Page_Load的時候執(zhí)行方法Response.Write(Request.Cookies['ASP.NET_SessionId'].Value),會輸出值,我的猜測是雖然你可以獲得ASP.NET_SessionId值,但實際上并沒有真正產生Session Cookie,因為此時當我試圖通過HttpWatch(下面介紹的工具)來查看此Session Cookie的時候根本查不到,當然這也只是我的個人猜測而已,至于具體的內部機制還是不甚了解。
當沒有使用Session的時候刷新頁面Session Cookie的值會變化嗎?答案是會的,測試方法如上,設置Session模式為SQLServer,在Page_Load的時候輸出Session Cookie的值,然后一直F5頁面即可,你會看到其值一直在變化,直到在代碼中明確地使用Session后便不再變化。
5. Session Cookie如何查看
如果設置了Session Cookie的過期時間,則此Session Cookie會保存在本地磁盤,一般是在目錄C:\Documents and Settings\user\Local Settings\Temporary Internet Files,此目錄可手工設置(Internet選項->常規(guī)->瀏覽歷史記錄中的'設置'選項->Internet臨時文件的'查看文件'選項)。
如果沒有設置過期時間,則Session Cookie默認是保存在瀏覽器內存中的,Chrome瀏覽器默認支持查看Cookie,具體步驟如下:Tools - > Settings ->Show Advanced Settings -> Privacy -> Content Settings -> Cookies -> All cookies and site data,不過坑爹的是它只支持查看和刪除,不支持修改,如果你想修改的話,我們只能通過第三方插件來完成https://chrome.google.com/webstore/detail/fngmhnnpilhplaeedifhccceomclgfbg(Chrome Web Store瀏覽下載安裝即可)
如果你使用的是IE瀏覽器,你也要通過安裝插件HttpWatch來查看(Firefox也適用)
五、Session的其它相關問題
1. 如何捕獲Global.asax中的Session_End()事件?