ASP.NET 狀態管理(cookie、Session)


cookie

       自定義 cookie 提供了保存備用數據的另一個選擇。cookie 在用戶的硬盤上創建一個小文件(臨時 cookie 保存在 Web 瀏覽器的內存)。

 

       cookie 的優點

  1. 對用戶透明,他們不必知道需要保存哪些信息。
  2. 很方便的由應用程序中的任意頁面使用,甚至還可以保存很久以便在不同的訪問中使用。

       cookie 的限制

  1. 和查詢字符串一樣,只能使用簡單的字符串信息
  2. 如果用戶找到並打開cookie文件,它們很容易被修改。因此不適合保存復雜,私有的信息或者大量的數據。
  3. 部分用戶還會禁用 cookie,不過大部分情況下用戶會接受 cookie,因為它們被太多的站點使用。

       cookie 的使用

  1. Request 對象和 Response 對象都提供了 Cookies 集合。
  2. 使用 Request 對象讀取 cookie
  3. 使用 Reesponse 對象設置 cookie
HttpCookie cookie = new HttpCookie("Preferences");      
cookie["Language"] = "English";
cookie["Country"] = "US";
Response.Cookies.Add(cookie);

 

       用這種方式添加的 cookie 在每次請求時都會回發,它直到用戶關閉瀏覽器時才會消失。但我們可以設置過期時間來設置長期存在的 cookie(以臨時 Internet 文件的形式存在用戶硬盤上)。

// This cookie lives for one year.
cookie.Expires = DateTime.Now.AddYears(1);

 

       使用 Request.Cookies 集合通過 cookie 的名字來讀取 cookie:

HttpCookie cookie = Request.Cookies["Preferences"];
 
// because the user could disable cookie,so must check it
string language;
if (cookie != null)
{
    language = cookie["language"];
}

 

       移除 cookie 的唯一方法是使用一個已過期的 cookie 來替換它:

HttpCookie cookie = new HttpCookie("LanguagePref");
cookie.Expires = DateTime.Now.AddYears(-3);
Response.Cookies.Add(cookie);

 

 

會話狀態 Session

       會話狀態時狀態管理最重要的一部分!通過它你可以在一個頁面存儲數據而另一個頁面獲取數據,最重要的是它還支持包括自定義數據類型在內的任意對象類型。每個訪問應用程序的客戶端都有不同的會話且包含不同的信息,因此 Session 是跨頁瀏覽時保存用戶購物車內容的理想場所

       Session 不是免費的,它迫使 Web 服務器在服務器內存中保存額外的信息,即使信息量很小,成百上千個用戶訪問網站時也很可能會迅速造成一場災難。

 

會話架構

       ASP.NET 使用一個唯一的 120 位標識符跟蹤會話,並使用一個私有的算法來生成這個值,從統計學上說可以保證這個值是唯一的且足夠隨機,從而惡意用戶不能反向設計或猜出指定用戶將要使用的值。

       這個值是客戶端和服務器端傳遞的唯一值。客戶端發送會話 ID 后,ASP.NET 查找相應的會話,從狀態服務器獲得序列化的數據並將其轉換為活動的對象,最后將這些對象放到可以用代碼訪問的集合,這個過程是自動完成的。

       我們知道,ASP.NET 處理 HTTP 請求時會經過一個包含不同模塊的管道鏈,這些模塊可以響應應用程序事件。鏈上的一個模塊是 SessionStateModule(在 System.Web.SessionState 命名空間中)

       SessionStateModule 模塊負責產生會話 ID,從外部提供程序中獲取會話數據,並把數據綁定到請求的上下文中。頁面處理完畢后,該模塊還會保存會話信息。但很重要的一點要明白,SessionStateModule 並不保存會話數據,而是會話狀態持久化在外部組件中,這些外部組件稱為狀態提供程序

 

       會話狀態時 ASP.NET 可插拔架構的另一個例子。狀態提供程序是可以實現 IHttpSessionState 接口的任意類,也就是說構建(或購買)一個新的 .NET 組件,你就可以自定義如何處理會話狀態。

       ASP.NET 有 3 個預建的狀態提供程序,它們允許你在 進程獨立服務(windows服務)SQL Server數據庫 中保存信息。

 

使用會話狀態

       可以通過 System.Web.SessionState.HttpSessionState 類和會話狀態交互,它建立在 Session 對象中,由 ASP.NET 網頁提供。

       會話狀態在下面這些情形下會丟失:

  1. 用戶關閉並重啟瀏覽器
  2. 用戶通過另一個瀏覽器訪問同一頁面(不同瀏覽器處理這一方式是不同的)
  3. 沒有活動導致會話超時,默認情況下,閑置 20 分鍾后會話會超時
  4. 程序員調用 Session.Abandon()方法結束會話

       在前2種情況下,會話其實還保存在服務器的內存中,Web 服務器並不知道用戶已經關閉了瀏覽器或者更換了窗口,會話在內存中游盪,但由於不能訪問到,直至最終過期。此外應用程序域重建時會話也會丟失,這個過程透明的發生。

 

HttpSessionState 成員

Count 當前會話集合中的項目數
IsCookieless 指示當前會話是存儲在 cookie 中還是嵌入在修改的 URL 中
IsNewSession 指示會話是否是只為當前請求而創建的
Mode 一個枚舉值,用於指示 ASP.NET 如何保存會話狀態信息
SessionID 當前客戶端的會話標識字符串
StaticObjects 通常不使用(為了向后兼容 ASP 程序的)
Timeout 超時的時長,該值可以通過代碼修改
Abandon() 立即取消當前會話並釋放它占用的全部內存空間,退出頁面時很有用,確保服務器內存得到快速重用
Clear() 不改變當前會話標識符的情況下清空所有的會話項目

 

 

配置會話狀態

       可以通過 web.config 文件中的 <sessionState> 元素為應用程序配置會話狀態,下面是所有可用設置的一個快速瀏覽:

<system.web>
<!-- Other settings omitted-->
 
<sessionState
     mode="Off|InProc|StateServer|SQLServer|Custom"
     stateConnectionString="tcpip=127.0.0.1:42424"
     stateNetworkTimeout="10"
     sqlConnectionString="data source=127.0.0.1;Integrated Security=SSPI"
     sqlCommandTimeout="30" allowCustomSqlDatabase="false"
     useHostingIdentity="trye|false"
     compressionEnabled="true|false"
     cookieless="UseCookies" cookieName="ASP.NET_SessionId"
     regenerateExpiredSessionId="true|false"
     timeout="20"
     customProvider=""
  />
</system.web>

1. Mode

       模式設置允許你配置在請求間保存會話狀態信息的會話狀態提供程序

       Off

              禁用應用程序中所有頁面的會話狀態管理

 

       InProc

              類似於傳統 ASP 中保存會話的方式,它指示 ASP.NET 在當前應用程序域中保存信息。這種方式有最好的性能卻具有最差的持久性,如果重啟服務器,狀態信息將丟失。InProc 是默認選項,它對於多數小型網站有意義,不過在 Web 集群中根本不能工作。你需要使用 SQL Server 狀態服務才能使會話狀態在服務器間共享。另一個不使用它的原因是它會產生較多的會話碎片。ASP.NET 應用程序會因為多種活動而回收,包括更改配置,更新頁面,如果你發現你的應用程序域不斷重啟而導致會話過早丟失,你可以選擇另一種更強健的會話狀態提供程序

 

使用進程外或 SQL Server狀態服務時,請記住你需要考慮更多的問題:

  • 使用 StateServer 或 SQLServer 模式時,要保存在會話狀態中的對象必須是可序列化的,否則 ASP.NET 不能夠將對象傳送到狀態服務器或保存到數據庫中
  • 如果在集群中,則需要一些額外的配置以保證所有 Web 服務器同步,否則服務器會采用不同的方式編碼會話狀態信息,當用戶由一台服務器路由到另一台服務器時會產生一個問題,解決該問題的辦法是修改 machine.config 文件的 <machineKey>節以確保所有服務器使用相同的設置。
  • 如果不使用進程內的狀態提供程序,SessionStateModule.End 事件就不會觸發,所有 global.asax或者HTTP模塊中所有注冊該事件的處理程序將被忽略

       StateServer

              采用該選項時 ASP.NET 使用一個獨立的 Windows 服務來管理狀態。即使該服務於 Web 服務器在同一台服務器上。它也會在 ASP.NET 主進程外加載,這樣當 ASP.NET 進程需要重啟時,可以為狀態提供基本的保護。代價是兩個進程間傳遞信息時將導致延遲,如果頻繁訪問和更改狀態信息,則速度會明顯變慢,讓人無法忍受

              使用 StateServer 選項時,要為 StateConnectionString 設置一個值。該值定義了運行服務的計算機的 TCP/IP 地址和端口號。當然,在應用程序能夠使用服務之前必須將其啟動。

              使用 StateServer 選項時還可以設置一個可選的 stateNetworkTimeout 特性,該特性指定放棄請求前等待服務器響應的最大秒數,默認值是 10 秒。

image

 

       SQL Server

              該選項指示 ASP.NET 使用 sqlConnectionString 特性設定的 SQL Server 數據庫保存會話信息。這是目前最具彈性同時也是目前最慢的狀態存儲方式,使用該模式需要一台裝有 SQL Server 的服務器。設置 sqlConnectionString 時通常需要指定數據源(服務器地址),除非使用 SQL 整合安全方式,否則還要指定用戶名和密碼。此外,還需要安裝臨時會話數據庫和一些特定的存儲過程。其中存儲過程負責保存和獲取會話信息。

              ASP.NET 使用命令行工具 aspnet_regsql.exe 實現這一目的。使用 aspnet_regsqt.exe 創建會話存儲數據庫時,要提供 -ssadd 參數,此外,使用 -S 參數表明數據庫服務器的名稱,-E 參數使用當前登錄的 Windows 用戶賬戶登錄數據庫。使用 -ssremove 參數可以移除 ASPState 數據庫

這個命令在當前計算機上創建會話存儲數據庫,使用默認的數據庫名稱 ASPState:

aspnet_regsql.exe -S localhost -E -ssadd

這個命令使用了假名 localhost ,它告訴 aspnet_regsql.exe 連接當前計算機上的數據庫服務器,可以用數據庫服務器所在的計算機名替代它。

              標准會話狀態超時時間也對 SQL Server 狀態管理有效。因為 aspnet_regsql.exe 工具同時還創建了一個名為 ASPState_Job_DeleteExpiredSessions 的新 SQL Server 執行計划。只要 SQLServerAgent 服務在運行,這個執行計划每分鍾執行一次。

              此外,每次重啟 SQL Server 時狀態表會被刪除,無論會話是否超時。這是因為此表是創建在 tempdb 數據庫里,它是一個臨時的存儲區域。如果這不是你所期望的行為,你可以告訴 aspnet_regsql.exe 在 ASPState 數據庫里安裝持久狀態表。這是可以使用參數 -sstype p(Persisted)

aspnet_regsql.exe -S localhost -E -ssadd -sstype p

現在,會話記錄將保存在數據庫里,即便重啟了 SQL Server 也是如此。

              最后一個選項是是創建一個非默認的狀態表,這時使用參數 -sstype c(Custom),並通過 -d 參數提供數據庫名稱。

aspnet_regsql.exe -S localhost -E -ssadd -sstype c -d MyCustomStateDb

采用這種方法創建的是持久會話表。

              如果使用了自定義數據庫,還需要對 web.config 做兩處微調:

<sessionState mode="SQLServer" allowCustomSqlDatabase="true" sqlConnectionString=
    "data source=localhost;Integrated Security=SSPI;Initial Catalog=MyCustomStateDb" />

 

       Custom

              使用自定義模式時,需通過 customProvider 特性指定會話狀態存儲提供程序。這個特性指向 App_Code 文件夾中一個類的名字,或者在 Bin 目錄或 GAC 中某個已編譯的程序集的名字。創建自定義狀態提供程序是一項需要小心處理的底層任務,需要保證安全性,穩定性和可擴展性,因此最好由可靠的第三方設計和測試

 

2. 壓縮

       他可以減小序列化會話數據的大小。把 enableCompression 設置為 true 后,會話數據在傳送到進程外會話狀態存儲時才起作用,因為這種情況下數據才會被序列化。

       會話數據是使用 System.IO.Compression.GZipStream 類自動進行壓縮的。

       會話狀態壓縮最有意義的兩個場景如下:

  • 在內存里存儲了大量會話狀態數據時:Web服務器內存是非常珍貴的資源。理想情況下,會話狀態用於少量的信息段,后端數據庫處理大量數據的長期儲存。但如果情況不是這樣並且進程外狀態服務器擁有大量的內存,壓縮式潛在的解決方案。
  • 在其他計算機存儲會話狀態數據時:在某些大型的 Web 應用程序中會話狀態是在進程外的(一般是 SQL Server)並且在單獨的計算機上。因此,ASP.NET 需要在網絡連接上傳送會話信息。顯然,這樣的設計降低了執行速度,不過,對於某些需要大量存儲會話狀態信息且流量非常大的網站而言,這仍然是最佳的折中方案。

       第一種情況,壓縮犧牲了 CPU 的時間換取了Web服務器內存。

       第二種情況,壓縮犧牲了 CPU 的時間節省了網絡流量。

注:

       實際的壓縮量由於數據類型的不同差異很大,但在微軟的測試中,客戶端得到 30% 到 60% 的數據減少,在這些場景中它確保了性能的極大提升。

 

3. cookieless

       HttpCookieMode 枚舉值:

UseCookies 無論瀏覽器或設備是否禁用 cookie,總是可以使用 cookie(默認選項)。
如果設備不支持 cookie,后續的請求會話信息會丟失,因為每次請求都會獲得新的標識符
UseUri 無論瀏覽器或設備是否支持 cookie,都不會使用 cookie。會話ID被存儲在URL中。
UseDeviceProfile ASP.NET 通過檢查 BrowserCapabilities 對象來決定是否使用無 cookie 會話。
(只指明了設備應當支持的---而沒有考慮用戶可能禁用了瀏覽器中的 cookie)
AutoDetect ASP.NET 通過嘗試設置和讀取cookie(一種常用的 Web 技術)來確定瀏覽器是否支持 cookie
該技術可以正確判斷瀏覽器是否支持 cookie 但卻禁用了 cookie,在這種情況下,將使用無 cookie 會話。

 

       使用無 cookie 模式時,例如下面這樣:

<sessionState cookieless="UseUri" 。。。>

       會話 ID 會自動插入到 URL 中,ASP.NET 獲得請求時,它將移除 ID,檢索會話集合,將請求送到相應的目錄:

http://localhost/WebApplication/(amfdddgd677sdgfdfg)/Page.aspx

       因為會話 ID 是插入到 URL 中的,所以相對鏈接也會自動獲得會話 ID,真正限制無 cookie 會話狀態的是:不能使用絕對鏈接,因為他們不包含會話 ID

 

       ASP.NET 默認允許重用會話標識。如果使用了一個含有過期會話的查詢字符串,ASP.NET 會用這個 ID 重新創建一個會話。問題是某個會話 ID 會不經意的出現在某些公共場合,例如作為搜索引擎的查詢結果。這樣多個用戶會使用同樣的會話 ID 來訪問服務器並加入到含有相同共享數據的相同會話中。為避免這一潛在的安全問題,使用無 cookie 會話時,推薦加入可選的 regenerateExpiredSessionId 特性,並把該值設為 true。這樣當用戶使用已經過期的會話 ID 時,會創建一個新的會話 ID。這么做的唯一缺點是,當前頁面所有視圖狀態和表單數據將全部丟失,因為 ASP.NET 執行了一次重定向來保證瀏覽器使用新的會話 ID

       可以通過 Session 對象的 IsCookieless 屬性來檢查當前是否在使用無 cookie 的會話。

 

4. timeout

       這個設置體現了會話狀態最重要的折中。不同的分鍾數會給服務器負載及應用程序性能帶來非常大的影響。理想狀態下,最佳的時間應當足夠短,保證服務器內存能及時釋放,同時這個時間也應該足夠長,保證客戶端在暫停一段時間后會話不會丟失還能繼續使用。

       可以在代碼中設置:

Session.Timeout = 10;

 

 

會話狀態安全

       會話狀態中的信息非常安全,因為它們只保存在服務器上。然而含有會話 ID 的 cookie 可能很容易被篡改。就是說一個惡意用戶可以偷走 cookie 然后在另一台計算機上繼續使用。

       一個常用的方法是使用自定義的會話模塊來檢查客戶端 IP 地址的變化。唯一真正有效的方法是僅在使用了 SSL 的網站上使用會話 cookie。采用這種方法,會話 cookie 被加密從而在其他計算機上不可用。如果使用這種方式,將會話 cookie 標識為安全 cookie 才有意義,這樣 cookie 只能通過 SSL 連接傳送。這使得用戶不能將 URL 由 https:// 修改為可以不使用 SSL 發送 cookie 的 http:// 。

Request.Cookies["ASP.NET_SessionId"].Secure = true;  // 這樣的 cookie 必須在使用了 SSL 的網站上傳送

這條代碼應在用戶通過驗證后立即使用,另外還要確保會話狀態中至少有一點信息,這樣它才不被取消。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM