Session 數據存儲於服務端,客戶端需攜帶唯一標識 SessionID 以關聯會話。SessionID 預設存放於 Cookie(名為 ASP.NET_SessionId)中,屬會話級 Cookie(瀏覽器關閉失效)。每次 HTTP 請求自動攜帶此 Cookie,服務端據此獲取對應 Session 數據。
常見誤區:初級開發者常以為 Session 與 Cookie 無關。實則 SessionID 依賴 Cookie 傳遞。若應用大量寫入 Cookie,可能導致瀏覽器 Cookie 數量/大小超限,致使 SessionID Cookie 被擠出或無法寫入,引發 Session 丟失。
public bool SetCookie(int day)
{
string cookieName = GetType().ToString();
HttpCookie sessionCookie = null;
// 1. 備份當前請求中的 SessionID
if (HttpContext.Current.Request.Cookies["ASP.NET_SessionId"] != null)
{
string sessionId = HttpContext.Current.Request.Cookies["ASP.NET_SessionId"].Value;
sessionCookie = new HttpCookie("ASP.NET_SessionId") { Value = sessionId };
}
// ... 中間業務邏輯省略 ...
// 2. 防禦性重寫:若 Cookie 總數超限(>20),優先確保 SessionID 寫入響應
if (HttpContext.Current.Request.Cookies.Count > 20 && sessionCookie != null && !string.IsNullOrEmpty(sessionCookie.Value))
{
HttpContext.Current.Response.Cookies.Remove("ASP.NET_SessionId");
HttpContext.Current.Response.Cookies.Add(sessionCookie);
}
return true;
}
此模式確保高負載、多 Cookie 場景下 SessionID 不丟失。
| 模式 | 存儲位置 | 性能 | 適用場景 |
|---|---|---|---|
| Off | 禁用 Session | 無 | 無狀態頁面、API 端點 |
| InProc (預設) | IIS 工作進程內存 (aspnet_wp.exe / w3wp.exe) | ★★★★★ 最高 | 單服務器、數據量小、容許重啟丟失數據 |
| StateServer | 獨立狀態服務 (aspnet_state.exe),可跨機器 | ★★★☆☆ 損耗 10-15% | Web 伺服器叢集、需進程隔離、不願維護 SQL |
| SQLServer | SQL Server 數據庫 | ★★☆☆☆ 損耗 10-20% | 高可用、持久化、大型叢集、需數據安全 |
| Custom | 自定義提供程序 (繼承 SessionStateStoreProviderBase) | 視實現而定 | Redis、MongoDB、分佈式緩存等特殊需求 |
本文重點講解 StateServer 與 SQLServer 兩種分佈式模式的搭建與優化。
services.msc 中找到 ASP.NET State Service,啟動類型改為 自動 並啟動。HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\aspnet_state\ParametersAllowRemoteConnection = 1 (0=僅本機)Port = 42424 (十進制,預設即此)。<configuration>
<system.web>
<sessionState
mode="StateServer"
stateConnectionString="tcpip=192.168.1.100:42424"
cookieless="false"
timeout="60" />
</system.web>
</configuration>
stateConnectionString:指向狀態服務器 IP:Port。cookieless="false":使用 Cookie 傳遞 SessionID (推薦)。設為 true 或 UseUri 會將 SessionID 嵌入 URL,影響 SEO 且有安全風險。timeout:滑動過期時間(分鐘)。C:\Windows\Microsoft.NET\Framework\[版本號]\InstallSqlState.sql:創建默認數據庫 ASPState (含 ASPStateTempSessions, ASPStateTempApplications 表),直接執行即可。InstallSqlStateTemplate.sql:自定義數據庫名。需將腳本中 [DatabaseNamePlaceHolder] 替換為目標名稱後執行。aspnet_regsql.exe -S . -U sa -P 123456 -ssadd -sstype p
-S:SQL 實例 (「.」表本機)-U/-P:SQL 登錄賬密;或用 -E 走 Windows 驗證-ssadd:添加 Session 數據庫;-ssremove 移除-sstype:t=tempdb (重啟丟失) | p=ASPState (持久化,**生產推薦**) | c=自定義庫 (需配合 -d 指定名稱)使用默認 ASPState 數據庫:
<sessionState
mode="SQLServer"
sqlConnectionString="server=192.168.1.100; uid=sa; pwd=123456;" />
使用自定義數據庫 (需 allowCustomSqlDatabase="true"):
<sessionState
mode="SQLServer"
allowCustomSqlDatabase="true"
sqlConnectionString="server=192.168.1.100; Database=MyAspState; uid=sa; pwd=123456;" />
關鍵權限:連接字符串用戶必須擁有 ASPState (或自定義庫) 和 tempdb 兩個庫的 db_owner 權限。
<machineKey> 配置完全相同 (validationKey, decryptionKey, validation, decryption),用於加解密序列化數據。[Serializable] 或實現 ISerializable。\LM\W3SVC\2 在所有節點完全一致。Machine.config/Web.config 中 <httpModules> 包含 SessionStateModule。Database=xxx 並開啟 allowCustomSqlDatabase。cookieless="UseUri" 嵌入 URL (不推薦)。.htm 未映射給 ASP.NET ISAPI,各框架可能生成不同 SessionID。解決:改 .aspx 或映射 .htm 給 ASP.NET 處理。Session.Abandon() 觸發。Session.Clear() 僅清數據不銷毀 Session。Response.Redirect/Server.Transfer。<processModel> 配置) 連接,可能登錄失敗。