轉:http://www.cnblogs.com/tonyqus/archive/2006/10/24/522618.html
1.理解Session State模式
儲存位置
InProc:session在伺服器中以使用中的物件方式儲存(aspnet_wp.exe)
StateServer: session被序列化並儲存在單獨的aspnet_state.exe的記憶體中。StateServer能夠運行在另一台伺服器上
SQLServer: session被序列化並儲存在SQL Server中
效能:
InProc:最快,但是session資料越多,web伺服器上消耗的記憶體也越多,它可能影響效能。
StateServer:當儲存基本類型(如string,integer等)資料時,在同一個測試環境中它比InProc慢15%。如果你儲存大量對象,序列化和還原序列化可能影響到效能
SQLServer:當儲存基本類型(如string,integer等)資料時,在同一個測試環境中它比InProc慢25%。它也有與StateServer一樣的序列化效能問題。
關於Out-of-Proc(OOP,非InProc)模式的效能提示
如果你使用OOP模式(即StateServer或SQLServer),session state中的序列化和還原序列化對象將成為你的主要效能消耗之一。對於基本類型,ASP.NET通過一種內部最佳化方法來完成序列化和還原序列化。(基本類型包括所有的數字類型(如Int, Byte, Decimal,String, DateTime, TimeSpan, Guid, IntPtr和UIntPtr等))
如果你有一個session變數(如一個ArrayList對象),且它不是一個基本類型,ASP.NET將使用BinaryFormatter來進行序列化和還原序列化,那可能會相對慢一些。
所以出於效能考慮,最好使用上面列出的基本類型來儲存所有的session state資料。例如,如果你需要儲存兩個東西,名字和地址,在session state中你既可以(方法a)使用兩個string session變數來儲存它們,也可以(方法b)建立一個內含兩個string的類來儲存它們,然後把這個類對象儲存在一個session變數中。出於效能考慮,你應該選擇方法a。
為了進一步理解這個主題,請看FAQ中的一個問題:“序列化和還原序列化如何在SqlServer和StateServer模式下工作”
健壯性
InProc:如果工作者進程(aspnet_wp.exe)進行資源回收或者應用程式定義域(appdomain)重啟動,session state就會丟失。這是因為session state是儲存在一個應用程式定義域的記憶體空間中的。對設定檔(如web.config和machine.config)的修改或者\bin目錄的任何改變(例如在你使用VS編譯應用程式後產生了一個新的dll)都可能引起重啟動,詳細請見KB324772。在1.0中,也有一個bug可能引起工作者進程重啟動,但這個bug在1.1中已經修複,見KB321792。
如果你使用的是IIS6.0,你可以在IIS Manager中找到Application Pools/DefaultAppPool,其中可以看到回收(Recycling)選項卡與效能(Performace)選項卡中是否有引起IIS工作者進程(w3svc.exe)停止工作的參數。
更多有關應用程式資源回收的內容,可以看我的另一篇FAQ:
http://www.asp.net/Forums/ShowPost.aspx?tabindex=1&PostID=232621
StateServer:解決了InProc模式的session state丟失問題。允許一個webfarm在中央伺服器中儲存session。只能在State Server上出現失敗。
SQLServer:與StateServer相似。session state的資料在SQL Server重啟後仍然保留著,你也可以按照KB311209的步驟使用SQL server failover cluster
警告
InProc:它不能在web garden模式下工作,因為在這個模式下會有多個aspnet_wp.exe在同一台機器上運行。建議在使用web garden使切換到State Server或SQL Server。僅在InProc模式下支援Session_End事件。
StateServer
- 在web farm中,請確認在所有的web伺服器上有相同的<machineKey>。KB313091描述了如何設定它。
- 請確保你的對象是可序列化的。詳見KB312112
- 為了在web farm中的不同web伺服器上維護session state,IIS Metabase中的網站應用程式程式路徑(如\LM\W3SVC\2)應該在所有的伺服器上保持一致(大小寫敏感)。詳見KB325056
SQLServer
- 在1.0中有一個bug,如果你在連接字串中指定integrity security(如"trusted_connection=true"或 "integrated security=sspi"),且你開啟了asp.net的身份類比,它將不會工作。這個問題在KB324479中有描述,不幸的是這份文檔中的描述和原因部分是錯誤的。不過已經有一個QFE fix對它作了修複,這個fix將包含在1.0 sp3中。這個問題在1.1中已經修複了。
- 請確認你的對象是可序列化的,否則你的請求可能被掛住,詳見KB312112。SQLServer模式的掛起問題已經在1.1中修複,KB324479的QFE fix也修複了這個問題。1.0 sp3也對這個問題作了修複。
- 為了在web farm中的不同web伺服器上維護session state,IIS Metabase中的網站應用程式程式路徑(如\LM\W3SVC\2)應該在所有的伺服器上保持一致(大小寫敏感)。詳見KB325056
其他資源
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/aspnetsessionstate.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/CachingArchch2.asp
http://www.411asp.net/home/tutorial/specific/web/sessions
2. FAQ問題列表
Q: session state在部分瀏覽器上工作,而在其他一些上不工作。為什麼呢?
Q: 在InProc模式中,為什麼我有時會丟失所有的session?
Q: session state在一些web伺服器上工作,但是在其他伺服器上不工作。
Q: 為什麼session state不可用?
Q: 為什麼session_end沒有觸發?
Q: 使用InProc模式時,為什麼我的session變數頻繁丟失?
Q: 在session逾時或刪除之後,為什麼SessionID保持不變
Q: 為什麼SessionID每一次請求都會改變
Q: Session.Abandon()和Session.Clear()有什麼區別
Q: session的Timeout屬性是一個滑動逾時值嗎?
Q: 我可以在ASP.NET和ASP之間共用session嗎?
Q: 我可以在web應用程式(例如虛擬目錄或者IIS的應用程式)間共用session state嗎?
Q: 在session state中可以儲存哪些類型的對象?
Q: 為什麼我的請求在切換到SQLServer模式之後掛住了?
Q: 為什麼Response.Redirect和Server.Transfer在Session_End中不工作?
Q: 在Session_End中,我可以獲得一個有效HttpSessionState對象和HttpContext對象嗎?
Q: 在web service中如何使用session?
Q:我正在寫一個HttpHandler,為什麼session stae不工作?
Q: 我正在使用web farm,並且每當我重新導向到其他伺服器時,session state就會丟失?
Q: 如果使用cookieless,我該如何從一個HTTP頁面重新導向到一個HTTPS頁面?
Q: session state有沒有一個鎖機制來安排對session的訪問順序?
Q: 我該如何檢測一個session到期,然後重新導向到另一個頁面
Q: 在Session_End中,我嘗試使用SQL做一些清理工作,但是失敗了,請問為什麼?
Q: 我使用的是SQLServer模式,為什麼我的session不會到期
Q: 我有一個以htm為副檔名的frameset頁面,並且我發覺其中包含的每個幀在第一次請求時都有一個不同的SessionID,這是為什嗎?
Q: 我將EnableSessionState設定為ReadOnly,但是在InProc模式下,我仍然可以修改session,為什嗎?
Q: 我將cookieless設定為true,在Redirect之後session變數丟失了,為什嗎?
Q: 將cookieless設定為true有哪些缺點
Q: 在InProc模式下,我用編程方式改變了session的逾時時間,它觸發了Session_End,為什嗎?
Q: 在SQLServer模式下,我可以把session state儲存在除tempdb之外的資料庫中嗎?
Q: 如何防止將未加密的字串放在我的連接字串匯總?
Q: 在使用SQLServer模式時,我需要怎樣的SQL許可權?
Q: 我可以自己寫定製的session state模式嗎?
Q: 在SQLServer或StateServer模式下,序列化和還原序列化如何工作?
Q: 我該如何讓我的state server更安全?
Q: 我能否可以使用非global.asax中的處理常式來訂閱SessionStateModule.End事件?
Q: 不同的應用程式可以把他們的session state儲存在同一個SQL Server上的不同資料庫中嗎?
Q: session state在部分瀏覽器上工作,而在其他一些上不工作。為什麼呢?
A: 估計你沒有使用cookieless,你必須保證你的瀏覽器支援cookie。請參考這份KB:http://support.microsoft.com/default.aspx?scid=kb;EN-US;q316112
Q: 在InProc模式中,為什麼我有時會丟失所有的session?
A: 請見理解session state模式的健壯性部分
Q: session state在一些web伺服器上工作,但是在其他伺服器上不工作。
A: 可能是機器名的問題,見http://support.microsoft.com/default.aspx?scid=kb;EN-US;q316112
Q: 為什麼session state不可用?
A:
- 首先,檢查web.config、machine.config和Page標籤來確認你啟用了session state
參考資料:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconsessionstate.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconpage.asp
- 請注意session state並非在任何地方、任何時間都可以使用,它僅在HttpApplication.AcquireRequestState事件之後可用。例如,在 global.asax中的Application_OnAuthenticateRequest處理常式中,session state不可用
- 請確認System.Web.SessionState.SessionStateModule已包含在設定檔的< httpModules>節中。一個常見的例子是,出於效能考慮,SharePoint應用程式會把這個模組從web.config檔案中移除,因此導致session不可用
Q: 為什麼session_end沒有觸發?
A: 這是最常見的問題之一
1. 請記住session_end僅在InProc模式中可用
2. 關閉瀏覽器,session_end是不會觸發的。HTTP是一種無狀態協議,伺服器沒有辦法知道你的瀏覽器是否已經關閉。
3. 當有n分鐘(n=timeout值)的無操作或調用Session.Abandon時,Session_End才會觸發
4. 對於情況1而言,Session_End將由一個後台線程觸發,這表示:
a. Session_End中的代碼使用工作者進程帳號運行,如果你訪問如資料庫這樣的資源時,可能會有許可權問題。
b. 如果在Session_End中發生錯誤,程式不會通知發生了什麼
5. 對於情況2而言,為了讓Session_End觸發,session state必須先存在。這意味著你必須在session state中儲存一些資料,並且已經完成了至少一個請求
6. 還是對於情況2而言,Session_End僅在被丟棄的session被找到的時候才會觸發。這樣的話,如果你在同一個請求中建立並丟棄一個 session,由於session沒有被儲存,因此也不會被找到,Session_End將不會被調用。這是v1.0和v1.1中的bug。
Q: 使用InProc模式時,為什麼我的session變數頻繁丟失?
A: 有可能是應用程式資源回收引起的,見http://support.microsoft.com/default.aspx?scid=kb;en-us;Q316148
在v1.0中有一個bug可能會導致工作者進程重啟動。在v1.1和v 1.0sp2中已經修複。見http://support.microsoft.com/default.aspx?scid=kb;EN-US;321792
關於應用程式資源回收的詳細資料,請見我的另一篇:FAQhttp://www.asp.net/Forums/ShowPost.aspx?tabindex=1&PostID=232621
Q: 在session逾時或刪除之後,為什麼SessionID保持不變
A: 儘管在逾時周期之後session state到期,sessionID將一直保持到瀏覽器session到期為止,也就是說,一個相同的sessionID可以有多次session逾時,但是始終對應著一個相同的瀏覽器執行個體。
Q: 為什麼SessionID每一次請求都會改變
A: 如果你的應用程式從未在session state中儲存過資料。在這種情況下,那麼每次請求都會建立一個新的session state(ID也是新的),但是不會被儲存,因為裡面什麼資料都沒有。
儘管如此,有兩種例外可能產生相同的Session ID
- 如果使用者使用相同的瀏覽器執行個體來請求另一個使用session state的頁面,那麼你每次獲得的Session ID是相同的。詳見“在session逾時或刪除之後,為什麼SessionID保持不變?”
- 如果使用了Session_OnStart事件,即使session為空白,asp.net也會儲存session state。
Q: Session.Abandon()和Session.Clear()有什麼區別
A: 主要的區別在於,如果你調用Session.Abandon(), Session_End將被觸發(僅在InProcxi下適用),在下一個請求中,Session_Start觸發。而Session.Clear()僅僅是清除資料,但沒有刪除session。
Q: session的Timeout屬性是一個滑動逾時值嗎?
A: Session的Timeout是一個滑動到期時間,意思是一旦你的頁面訪問session state,到期時間就會向挪。注意,只要頁面沒有被禁用,在請求時頁面就會自動訪問session
Q: 我可以在ASP.NET和ASP之間共用session嗎?
A:不可以。但是有一篇文章講到了如何來繞過這個問題:http://www.msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/ConvertToASPNET.asp
當然也有一些第三方解決方案。
Q: 我可以在web應用程式(例如虛擬目錄或者IIS的應用程式)間共用session state嗎?
A:不能。
Q: 在session state中可以儲存哪些類型的對象?
A:這是由你使用的模式決定的
- 如果你使用的是InProc模式,儲存在session state中的對象是活對象,那麼你就可以儲存你建立的任何對象
- 如果你使用的是SQLServer或State Server模式,當處理一個請求時,session state中的對象對象將被序列化和還原序列化,所以請確認你的對象都是可序列化的,而它們的類都作了可序列化標記。如果沒有,session state將不會成功儲存。在v1.0中,有一個bug,當這個問題發生時,如果使用SQLServer模式,請求可能在不知情的情況下被掛起。掛起的問題在v1.1和v1.0 sp3中已經修複。KB324479的QFE fix也包含了對這一問題的修複。
更多資訊請見:http://support.microsoft.com/directory/article.asp?ID=KB;EN-US;q312112
Q: 為什麼我的請求在切換到SQLServer模式之後掛住了?
A:請看問題“在session state中可以儲存哪些類型的對象?”的答案
Q: 為什麼Response.Redirect和Server.Transfer在Session_End中不工作?
A:Session_End是在伺服器內部觸發的,它基於一個內部的計時器。因此,在事件觸發時,與任何HttpRequest對象無關。這也是為什麼Response.Redirect 和Server.Transfer不工作的原因。
Q: 在Session_End中,我可以獲得一個有效HttpSessionState對象和HttpContext對象嗎?
A: 你可以獲得httpSessionState對象,你可以使用'Session'來訪問該對象。但是你無法訪問HttpContext,因為這個事件和請求沒有任何關係。
Q: 在web service中如何使用session?
A: 需要在調用方使用一些技巧,你必須儲存web服務使用的cookie。請見關於HttpWebClientProtocol.CookieContainer的MSDN文檔。
儘管如此,如果你是通過代理對象從你的頁面調用web服務,由於架構限制,web服務和你的頁面無法共用session state。
如果你通過redirect調用web服務,這是可以完成的
Q:我正在寫一個HttpHandler,為什麼session stae不工作?
A: 你的HttpHandler介面必須實現標記介面IRequiresSessionState或IReadOnlySessionState,方能使用session state。
Q: 我正在使用web farm,並且每當我重新導向到其他伺服器時,session state就會丟失?
A: 為了在web farm中的不同伺服器之間維護session state,IIS Metabase中的網站應用程式程式路徑(例如 \LM\W3SVC\2)應該在所有的web伺服器上保持一致(大小寫敏感)。詳見KB325056
Q: 如果使用cookieless,我該如何從一個HTTP頁面重新導向到一個HTTPS頁面?
A: 嘗試使用下面的代碼:
String originalUrl = "/fxtest3/sub/foo2.aspx";
String modifiedUrl = "https://localhost" + Response.ApplyAppPathModifier(originalUrl);
Response.Redirect(modifiedUrl);
Q: session state有沒有一個鎖機制來安排對session的訪問順序?
A:session state實現了讀寫鎖定機制:
- 對session state有寫入權限(如<%@ Page EnableSessionState="True" %> )的頁面或幀將獲得這個session的寫鎖,直到請求結束。
- 對session state有讀許可權(如<%@ Page EnableSessionState="ReadOnly" %> )的頁面或幀將獲得這個session的讀鎖,直到請求結束。
- 讀鎖會阻塞寫鎖;讀鎖不會阻塞讀鎖;寫鎖會阻塞所有的讀鎖和寫鎖
- 這也是為什麼當兩個幀同時擁有session的存取權限時,一個幀必須等待另一幀先完成
Q: 我該如何檢測一個session到期,然後重新導向到另一個頁面
A: 這是經常要遇到的問題,但不幸的是沒有很簡單的方法來完成它。我們將期待在一個主要版本中實現它。同時,如果你使用cookie,你可以在cookie中儲存一個標誌,這樣你就可以區分新瀏覽器+新session及舊瀏覽器+到期session,下面的代碼在session到期時會重新導向到一個到期頁面。
void Session_OnStart(Object sender, EventArgs e) {
HttpContext context = HttpContext.Current;
HttpCookieCollection cookies = context.Request.Cookies;
if (cookies["starttime"] == null) {
HttpCookie cookie = new HttpCookie("starttime", DateTime.Now.ToString());
cookie.Path = "/";
context.Response.Cookies.Add(cookie);
}
else {
context.Response.Redirect("expired.aspx");
}
}
Q: 在Session_End中,我嘗試使用SQL做一些清理工作,但是失敗了,請問為什麼?
A: 首先,session_End僅在InProc模式下支援。
第二,Session_End是用運行工作者進程(aspnet_wp.exe)的帳號啟動並執行,這個帳號可以在machine.config中指定。因此,在你的Session_End中,如果使用integrity security串連SQL,它將使用工作者進程帳號身份串連,這可能會引起登入失敗,這要看你的SQL安全設定了。
Q: 我使用的是SQLServer模式,為什麼我的session不會到期
A: 在SQLServer模式下,session到期是由SQL Agent使用一個註冊任務完成的,請確認你的SQL Agent是否已經運行。
Q: 我有一個以htm為副檔名的frameset頁面,並且我發覺其中包含的每個幀在第一次請求時都有一個不同的SessionID,這是為什嗎?
A: 原因是你的frameset頁面是一個htm檔案而不是一個aspx頁面
在通常情況下,如果一個frameset頁為一個aspx檔案,當你請求該頁面時,會首先發請求給web伺服器,你會收到一個asp.net session cookie(其中儲存著session id),然後瀏覽器會為frame發送一個單獨的請求,而每個請求將擁有相同的session id。
然而,因為你的頁面是一個htm檔案,第一個請求就不會獲得任何session cookie,因為頁面是由asp處理的而非asp.net,然後瀏覽器會為每個幀發送單獨的請求。但是,這次每個單獨的請求將不會持有任何 session id,這樣的話每個幀將建立自己的session。這也是為什麼你在每個幀中看到的session id都不同。最後一個請求將贏得勝利,因為它將覆蓋前兩個請求寫入的cookie。如果你重新整理一次,你將看到它們擁有了相同的session id。
這個行為是設計所決定的,簡單的解決方案就是將frameset頁面改稱aspx
Q: 我將EnableSessionState設定為ReadOnly,但是在InProc模式下,我仍然可以修改session,為什嗎?
A: 儘管那些EnableSessionState被設定為ReadOnly,但是在InProc模式中,使用者仍然可以修改session。唯一的區別在於session在請求中不會被鎖住,這一限制是設計所決定的。對於這一點沒有在msdn中提到我表示抱歉。
Q: 我將cookieless設定為true,在Redirect之後session變數丟失了,為什嗎?
A: 如果你使用的是cookieless,你必須使用相對路徑(如..\hello.aspx),而不是絕對路徑(如\foo\bar\hello.aspx)。如果你使用的是絕對路徑,ASP.NET不會將session id儲存在url中。
Q: 將cookieless設定為true有哪些缺點
A: 設定cookieless=true表示一些潛在的規則,主要有:
1. 你不能在你的頁面中使用絕對路徑
2. 在http和https之間切換的話,你必須做一些額外的動作
3. 如果你的客戶發送了一個連結到一個朋友,URL將包含session id,兩個使用者可以在同一時間使用相同的session id
Q: 在InProc模式下,我用編程方式改變了session的逾時時間,它觸發了Session_End,為什嗎?
A: 這是InProc的一個bug。如果你更改session的timeout值為另一個值,Session_End將被調用(但不會調用Session_Start)。我們期待在v2.0中能夠修複這個錯誤。
Q: 在SQLServer模式下,我可以把session state儲存在除tempdb之外的資料庫中嗎?
A: 是的。見KB311209。
Q: 如何防止將未加密的字串放在我的連接字串匯總?
A: 見sql trusted connection或者將連接字串以加密資料形式儲存在註冊表中。詳情請見,KB329250和KB329290。
Q: 在使用SQLServer模式時,我需要怎樣的SQL許可權?
A: 調用者需要對下面的預存程序擁有EXEC許可權,
dbo.TempGetAppID
dbo.TempGetStateItem
dbo.TempGetStateItemExclusive
dbo.TempReleaseStateItemExclusive
dbo.TempInsertStateItemLong
dbo.TempInsertStateItemShort
dbo.TempUpdateStateItemLong
dbo.TempUpdateStateItemShort
dbo.TempUpdateStateItemShortNullLong
dbo.TempUpdateStateItemLongNullShort
dbo.TempRemoveStateItem
dbo.TempResetTimeout
在v1.1中,你也需要對下面的預存程序擁有EXEC許可權
dbo.TempGetStateItem2
dbo.TempGetStateItemExclusive2
請注意預存程序的擁有者必須對session state表(dbo.ASPStateTempSessions和 dbo.ASPStateTempApplications)擁有SELECT/INSERT/UPDATE/DELETE 許可權。通常,擁有者是執行installsqlstate.sql(或者持久版本,見KB311209)的帳號來安裝sql session state需要的表、預存程序、資料庫
也請注意,如果你的session state表在tempdb中(預設情況下)如果你對SQL Server進行資源回收,所有在這張表上的使用權限設定將丟失。
Q: 我可以自己寫定製的session state模式嗎?
A:(待翻譯)
Q: 在SQLServer或StateServer模式下,序列化和還原序列化如何工作?
A: (待翻譯)
Q: 我該如何讓我的state server更安全?
A:如果state server和web server運行在一台機器上,通過設定HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ aspnet_state\Param ters\AllowRemoteConnection的dword項為0,可以讓state server僅在本地運行。這樣就可以防止遠程用戶端連見到state server上。這一特性在v1.1中可用,在v1.0 sp3中也有。
state server必須受防火牆保護,以防止外部串連以保證真正安全。預設的連接埠是TCP 42424,你可以設定HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ aspnet_state\Param ters\Port來改變它。如果是本地模式,除了127.0.0.1以外,屏蔽所有外來串連;如果是遠程模式,顯式的禁用所有的地址,除了對wev伺服器的串連。
使用IPSec是另一種保護state server的方式。
Q: 我能否可以使用非global.asax中的處理常式來訂閱SessionStateModule.End事件?
A: 答案是否定的。當SessionStateModule觸發End事件時,只有定義在global.asax中的方法才會被觸發
這是出於安全原因考慮的才對此進行限制。假設asp.net允許使用者使用的其他的處理常式來處理End事件。在這種情況下,使用者通常使用一個頁面方法作為處理常式,當你在事件訂閱時傳入處理常式,處理常式將與你的程式運行在的HttpApplication執行個體關聯。請注意, HttpApplication執行個體會被回收來處理其他請求。這樣的話,當End事件觸發時,asp.net將調用處理常式,而與之關聯的 HttpApplication執行個體已經被另一個請求所使用,這樣的情況將引發各種各樣的問題。為了避免這種危險,在v1.0中決定進調用 Global.asax中定義的方法。希望你們都可以忍受這一限制。
Q: 不同的應用程式可以把他們的session state儲存在同一個SQL Server上的不同資料庫中嗎?
A: 答案是肯定的。詳情請見:http://support.microsoft.com/default.aspx?scid=kb;EN-US;836680