Share via


實作工作階段狀態存放區提供者

更新:2007 年 11 月

說明自訂工作階段狀態存放區提供者的實作,並示範實作範例提供者。

ASP.NET 工作階段狀態設計的目的,是為了讓您能夠在不同的來源中存放使用者工作階段。根據預設,工作階段狀態的值和資訊會儲存在 ASP.NET 處理序所在的記憶體中。將工作階段資料存放在狀態伺服器中是一個作法,這樣就可以在個別處理序中保持工作階段資料,而且如果關閉並重新啟動 ASP.NET 應用程式,便能保留住工作階段資料。另一個作法是在 SQL Server 資料庫中儲存工作階段資料,而多重 Web 伺服器可以在該資料庫中共用此資料。

您可以使用 ASP.NET 所包含的工作階段狀態存放區,或是實作自己的工作階段狀態存放區提供者。基於以下原因,您可能會建立自訂工作階段狀態存放區提供者:

  • 您需要將工作階段狀態資訊儲存於 SQL Server 以外的資料來源,例如 FoxPro 資料庫或 Oracle 資料庫。

  • 您在管理工作階段狀態資訊時所需要使用的資料庫結構描述,不同於提供者 (隨附於 .NET Framework) 所使用的資料庫結構描述。這種情況的範例便是購物車資料,此種資料是以預先定義的結構描述存放在現有的 SQL Server 資料庫中。

您可以建立繼承 SessionStateStoreProviderBase 類別的類別,來實作自訂的工作階段狀態存放區提供者。如需詳細資訊,請參閱稍後本主題中的「必要的類別」一節。

工作階段狀態模組

工作階段狀態是由 SessionStateModule 類別管理,它會在要求期間的不同時間點呼叫工作階段狀態存放區提供者讀寫工作階段資料至資料存放區。在要求開始時,SessionStateModule 執行個體 (Instance) 會藉由呼叫 GetItemExclusive 方法,或是呼叫 GetItem 方法 (如果 EnableSessionState 網頁屬性已設為 ReadOnly),從資料來源中擷取資料。在要求結束時,如果工作階段狀態值已經修改過,SessionStateModule 執行個體會呼叫 SessionStateStoreProviderBase.SetAndReleaseItemExclusive 方法將更新值寫入工作階段狀態存放區。SessionStateModule 不但會呼叫 SessionStateStoreProviderBase 實作的其他成員來初始化新工作階段,而且會在 HttpSessionState.Abandon 方法被呼叫時,從資料存放區中刪除工作階段資料。稍後本主題中的「必要的類別」一節,將進一步討論 SessionStateStoreProviderBase 類別中的每個成員。

SessionStateModule 類別會自行判斷 SessionID 值,而不是依賴工作階段狀態存放區提供者來完成此項動作。如果必要,藉由建立繼承 ISessionIDManager 介面的類別,您可以實作自訂的 SessionIDManager。如需詳細資訊,請參閱 ISessionIDManager 中的<備註>一節。

SessionStateModule 將會還原成 ASP.NET 處理序識別來存取任何保全資源,例如資料庫伺服器。如果將 <sessionState> 組態項目的 useHostingIdentity 屬性設為 false,即可指定 SessionStateModule 執行個體模擬 IIS 提供的識別。例如,假設您已將 IIS 應用程式設為使用 Windows 整合安全性,並想要讓 ASP.NET 模擬 IIS 提供的識別來管理工作階段,請為該應用程式在 Web.config 檔案的 <system.web> 組態區段中指定 <identity impersonate="true" />,同時將 <sessionState> 組態項目的 useHostingIdentity 屬性設為 false。如果 useHostingIdentity 屬性為 true,則 ASP.NET 會在連接至資料來源時模擬處理序識別,或是模擬提供給 <identity> 組態項目的使用者憑證 (如果有的話)。如需 ASP.NET 處理序識別的詳細資訊,請參閱設定 ASP.NET 處理序識別ASP.NET 模擬

鎖定工作階段存放區資料

ASP.NET 為多執行緒應用程式,因此可以回應多個同時發生的要求,但多個同時發生的要求可能會試圖存取同一個工作階段資訊,所以必須考量框架組內的多個框架都參考同一個應用程式中的 ASP.NET Web 網頁之情況。框架組內每個框架的個別要求可能會在 Web 伺服器上同時以不同的執行緒執行。如果各個框架的 ASP.NET 網頁存取工作階段狀態變數,則可能同時會有多個執行緒存取工作階段存放區。為了避免工作階段存放區的資料衝突以及未預期的工作階段狀態行為,SessionStateModuleSessionStateStoreProviderBase 類別中所包含的功能會在 ASP.NET 頁面執行期間,以獨佔方式鎖定特定工作階段的工作階段存放區項目。請注意,如果 EnableSessionState 屬性標示為 ReadOnly,則工作階段存放區的項目將不會鎖定。不過,同一個應用程式中的其他 ASP.NET 網頁也許可以寫入工作階段存放區,因此來自存放區的唯讀工作階段資料要求可能仍然必須等待鎖定的資料被釋放。

GetItemExclusive 方法的呼叫中,要求開始時即立刻鎖定工作階段存放區的資料。要求完成後,鎖定會在呼叫 SetAndReleaseItemExclusive 方法期間解除。

如果 SessionStateModule 執行個體在 GetItemExclusiveGetItem 方法的呼叫期間遇到鎖定的工作階段資料,它將每隔半秒鐘重新要求工作階段資料,直到鎖定被釋放或是 ExecutionTimeout 屬性中所指定的時間已經超過為止。如果要求逾時,SessionStateModule 會呼叫 ReleaseItemExclusive 方法,釋放工作階段存放區資料並在那時要求工作階段存放區資料。

在呼叫目前回應的 SetAndReleaseItemExclusive 方法之前,鎖定的工作階段存放區資料可能會在個別執行緒中因呼叫 ReleaseItemExclusive 方法而先釋放。這可能會使 SessionStateModule 執行個體設定並釋放先前已經由其他工作階段釋放並修改的工作階段狀態存放區資料。為了避免這種情況,SessionStateModule 針對每個要求都會包含鎖定識別項,以修改鎖定的工作階段存放區資料。只有在資料存放區中的鎖定識別項與 SessionStateModule 提供的鎖定識別項相符時,才會修改工作階段存放區資料。

刪除過期的工作階段存放區資料

當對工作階段呼叫 Abandon 方法時,會使用 RemoveItem 方法從資料存放區中刪除該工作階段的資料,否則資料會繼續留在工作階段資料存放區中,以供工作階段的未來要求使用。

刪除過期工作階段資料的機制需視資料來源的功能而定。如果資料來源可設為依據工作階段 Timeout 屬性刪除過期的工作階段資料,則您可以使用 SetItemExpireCallback 方法來參考 Session_OnEnd 事件的委派 (Delegate),並在刪除過期的工作階段資料時引發此事件。

ApplicationName

為了維持工作階段範圍,工作階段狀態提供者會為每個應用程式存放唯一的工作階段資訊。這可讓多重 ASP.NET 應用程式使用相同的資料來源,即使遇到重複的工作階段識別項也不會產生衡突。

由於工作階段狀態存放區提供者為每個應用程式存放唯一的工作階段資訊,因此您必須確認資料結構描述、查詢和更新都包含應用程式名稱。例如,下列命令可能用來從資料庫中擷取工作階段資料。

SELECT * FROM Sessions 
  WHERE SessionID = 'ABC123' AND ApplicationName = 'MyApplication'

或者,您可以將工作階段識別項和應用程式名稱的組合,儲存為工作階段狀態資料存放區中某一項目的唯一識別項。

必要的類別

若要實作工作階段狀態存放區提供者,請建立繼承 SessionStateStoreProviderBase 抽象類別 (Abstract Class) 的類別。SessionStateStoreProviderBase 類別會依次繼承 ProviderBase 抽象類別,所以您必須也要實作 ProviderBase 類別的必要成員。下表列出您必須從 ProviderBaseSessionStateStoreProviderBase 抽象類別中實作的必要屬性及方法,並提供每一項的說明。若要檢視每一成員的實作,請參閱工作階段狀態存放區提供者範例

必要的 ProviderBase 成員

成員

說明

Initialize 方法

需輸入提供者的名稱和組態設定的 NameValueCollection 執行個體。這個方法用於設定提供者執行個體的屬性值,其中包括組態檔 (Machine.config or Web.config) 中指定之實作特定的值和選項。

必要的 SessionStateStoreProvider 成員

成員

說明

InitializeRequest 方法

需輸入目前要求的 HttpContext 執行個體,並執行工作階段狀態存放區提供者所要求的任何初始設定。

EndRequest 方法

需輸入目前要求的 HttpContext 執行個體,並且執行工作階段狀態存放區提供者所要求的任何清除動作。

Dispose 方法

釋放工作階段狀態存放區提供者不再使用的任何資源。

GetItemExclusive 方法

需輸入目前要求的 HttpContext 執行個體和目前要求的 SessionID 值。從工作階段資料存放區擷取工作階段值和資訊,並在要求的期間鎖定資料存放區中工作階段項目的資料。GetItemExclusive 方法可設定數個輸出參數值,這些值會通知資料存放區中目前工作階段狀態項目相關的 SessionStateModule 呼叫。

如果資料存放區中找不到工作階段項目的資料,GetItemExclusive 方法會將 locked 輸出參數設定為 false 並傳回 null。這樣會使 SessionStateModule 呼叫 CreateNewStoreData 方法,為要求建立新的 SessionStateStoreData 物件。

如果資料存放區中找到了工作階段項目的資料,但資料為鎖定狀態,則 GetItemExclusive 方法將 locked 輸出參數設定為 true,將 lockAge 輸出參數設定為目前的日期與時間減去鎖定項目時的日期與時間,將 lockId 輸出參數設定為擷取自資料存放區的鎖定識別項,並傳回 null。這樣會使 SessionStateModule 每隔半秒鐘後再次呼叫 GetItemExclusive 方法,進而試圖擷取工作階段項目資訊並獲得對資料的鎖定。如果 lockAge 輸出參數所設定的值超過 ExecutionTimeout 值,則 SessionStateModule 會呼叫 ReleaseItemExclusive 方法,清除對工作階段項目資料的鎖定,然後重新呼叫 GetItemExclusive 方法。

當 regenerateExpiredSessionId 屬性設為 true 時,actionFlags 參數是和 Cookieless 屬性設為 true 的工作階段一起使用。actionFlags 值若設定為 InitializeItem (1),表示工作階段資料存放區中該項目是要求初始設定的新工作階段。工作階段資料存放區中的未初始化項目,是藉由呼叫 CreateUninitializedItem 方法建立的。如果來自工作階段資料存放區的項目已經初始化,則會將 actionFlags 參數設為零。

如果提供者支援無 Cookie 工作階段,請將 actionFlags 輸出參數設為目前項目從工作階段資料存放區傳回的值。如果要求的工作階段存放區項目的 actionFlags 參數值等於 InitializeItem 列舉值 (1),則 GetItemExclusive 方法在設定 actionFlagsout 參數之後應該將資料存放區中的值設為零。

GetItem 方法

這個方法執行的工作與 GetItemExclusive 方法相同,但它不會試圖鎖定資料存放區中的工作階段項目。當 EnableSessionState 屬性設定為 ReadOnly 時,會呼叫 GetItem 方法。

SetAndReleaseItemExclusive 方法

需輸入目前要求的 HttpContext 執行個體、目前要求的 SessionID 值、SessionStateStoreData 物件 (其包含要存放的目前工作階段值)、目前要求的鎖定識別項,以及指示要儲存之資料是屬於新工作階段還是屬於現有工作階段的值。

如果 newItem 參數為 true,則 SetAndReleaseItemExclusive 方法會以提供的值將新項目插入至資料存放區,否則資料存放區中的現有項目會被更新為提供的值,並且釋放對資料的任何鎖定。請注意,只有與提供的 SessionID 值和鎖定識別項值相符的目前應用程式工作階段資料才會被更新。

在呼叫 SetAndReleaseItemExclusive 方法之後,SessionStateModule 會呼叫 ResetItemTimeout 方法,更新工作階段項目資料的到期日與時間。

ReleaseItemExclusive 方法

需輸入目前要求的 HttpContext 執行個體、目前要求的 SessionID 值和目前要求的鎖定識別項,並釋放工作階段資料存放區中對項目的鎖定。這個方法會在呼叫 GetItemGetItemExclusive 方法,而且資料存放區指定要求的項目處於鎖定狀態,但鎖定時間已經超過 ExecutionTimeout 值時呼叫。這個方法會清除鎖定狀態,將項目釋出供其他要求使用。

RemoveItem 方法

需輸入目前要求的 HttpContext 執行個體、目前要求的 SessionID 值和目前要求的鎖定識別項,並從資料項目與提供的 SessionID、目前應用程式及提供的鎖定識別項相符的資料存放區中刪除工作階段資訊。呼叫 Abandon 方法時,會一併呼叫這個方法。

CreateUninitializedItem 方法

需輸入目前要求的 HttpContext 執行個體、目前要求的 SessionID 值和目前要求的鎖定識別項,並以 InitializeItem 的 actionFlags 值將未初始化的項目加入至工作階段資料存放區。

當 regenerateExpiredSessionId 屬性設為 true 時 (如果遇到過期的工作階段 ID 時,這會使 SessionStateModule 產生新的 SessionID 值),CreateUninitializedItem 方法是和無 Cookie 工作階段一起使用。

產生新 SessionID 值的程序需要瀏覽器重新導向至含有新產生之工作階段 ID 的 URL。在含有過期工作階段 ID 的初始要求期間,會呼叫 CreateUninitializedItem 方法。在 SessionStateModule 取得新 SessionID 值以取代過期工作階段 ID 之後,它會呼叫 CreateUninitializedItem 方法將未初始化的項目加入至工作階段資料存放區。然後,瀏覽器會重新導向到一個內含新產生 SessionID 值的 URL。工作階段資料存放區中有未初始化的項目可以確保含有新產生之 SessionID 值的重新導向要求沒有被誤認為是過期的工作階段,而是被視為新的工作階段。

工作階段資料存放區中未初始化的項目會與新產生的 SessionID 值關聯,並只包含預設值 (包括到期日與時間、對應到 GetItemGetItemExclusive 方法之 actionFlags 參數的值)。工作階段資料存放區中未初始化項目所包含的 actionFlags 值,應等於 InitializeItem 列舉值 (1)。這個值會經由 GetItemGetItemExclusive 方法傳遞給 SessionStateModule,並為 SessionStateModule 指定目前工作階段為新的工作階段。之後,SessionStateModule 將初始化新的工作階段,並引發 Session_OnStart 事件。

CreateNewStoreData 方法

需輸入目前要求的 HttpContext 執行個體和目前工作階段的 Timeout 值,並以空白 ISessionStateItemCollection 物件、HttpStaticObjectsCollection 集合和指定的新 Timeout 值來傳回新 SessionStateStoreData 物件。使用 GetSessionStaticObjects 方法可以擷取 ASP.NET 應用程式的 HttpStaticObjectsCollection 執行個體。

SetItemExpireCallback 方法

以參考到 Global.asax 中所定義的 Session_OnEnd 事件之委派當做輸入。如果工作階段狀態存放區提供者支援 Session_OnEnd 事件,則會設定 SessionStateItemExpireCallback 參數的區域參考並且該方法會傳回 true,否則會傳回 false。

範例提供者

若要檢視管理 Access 資料庫中工作階段資訊之自訂工作階段狀態存放區提供者的範例實作,請參閱工作階段狀態存放區提供者範例

請參閱

概念

工作階段狀態存放區提供者範例

ASP.NET 工作階段狀態概觀

ASP.NET 狀態管理概觀