使用服務之應用程式的效能考量
更新:2007 年 11 月
這個主題會討論一些在使用 ASP.NET 成員資格、角色、設定檔屬性、工作階段狀態、Web 組件個人化和站台巡覽時的效能最佳化。
成員資格
這個章節包括有效率地使用 ASP.NET 成員資格的相關資訊。
有效率地蒐集成員資格清單
呼叫 Membership 類別的方法時,請呼叫採用 PageIndex 和 PageSize 成員的多載方法。這些多載的執行速度會更快,因為它們會從 Web 伺服器傳輸更少的資料。其中一個範例是 Membership 類別的 GetAllUsers 方法。如果不使用任何參數呼叫 GetAllUsers 方法,就會傳回所有成員資格使用者。反之,呼叫 GetAllUsers 多載就只會傳回一頁的使用者,進而減少頁面所處理的資料量。
取得線上使用者數目時快取結果
您可以呼叫 GetNumberOfUsersOnline 方法來顯示網站上視為現用的使用者數目。這個方法會在每次呼叫方法時,檢查成員資格資料表中每個資料列,所以如果資料庫中的使用者數目很龐大,就會造成顯著的負面效能影響。請在必要時才呼叫此方法,而且如果您不需要確切的數目時,請快取該值一段時間。
角色
根據預設,每次載入頁面時,就會自動呼叫 GetRolesForUser 方法,而且會傳回使用者所屬的角色。這些角色會儲存在 RolePrincipal 物件的字典中。當 Web 網頁執行時,就會使用這個字典執行角色檢查。若要避免在每次載入頁面時存取提供者,進而減少伺服器處理時間,請將應用程式 Web.config 檔中的 CacheRolesInCookie 屬性 (Attribute) 設定為 true。這樣會讓使用者角色清單儲存在 Cookie 中。在後續載入頁面時,就可以從 Cookie 讀取角色資訊,而不用使用提供者的呼叫。
GetRolesForUser 方法、IsInRole 屬性和 GetRoles 方法都可以在程式碼中用於確認角色的成員資格。透過瞭解這些方法的互動方式,您就可以撰寫應用程式的程式碼,以便有效率地針對您想要執行的工作運作。
GetRolesForUser 方法永遠會存取提供者。當 Cookie 快取未啟用時,呼叫 IsInRole 方法永遠會導致在首次要求頁面時呼叫 GetRolesForUser 方法。如果 Cookie 快取已啟用,IsInRole 方法的呼叫就會改用在 Cookie 中快取的角色資訊。不論 Cookie 快取是否開啟,首次呼叫 GetRoles 方法都會導致呼叫 GetRolesForUser 方法。不過,頁面上對 GetRoles 方法的後續呼叫則會使用在 RolePrincipal 內部快取的角色資訊。
注意事項: |
---|
在 Cookie 中儲存敏感性資訊可能會將該項資訊公開 (Expose) 給使用者。為了獲得最佳的安全性,請勿啟用 Cookie 快取。 |
設定檔屬性
如果您的程式碼會存取任何設定檔屬性,則在載入頁面時,設定檔提供者就會讀取目前使用者的所有設定檔屬性 (具體來說,提供者會讀取與該設定檔提供者相關聯的所有屬性)。如果任何設定檔屬性值變更,當卸載頁面時,新的資訊就會寫入提供者資料存放區。ASP.NET 可以判斷內建 (Intrinsic) 型別 (例如整數和字串) 是否已變更,不過無法判斷非內建 (Non-Intrinsic) 型別是否已變更。
判斷設定檔屬性是否已儲存的演算法如下所示:
如果所有設定檔屬性型別都是內建型別且尚未變更,則設定檔就不會寫入資料存放區。
如果所有設定檔屬性型別都是內建型別且已經變更,則所有設定檔屬性值都會寫入資料存放區。
如果有任何屬性不是內建型別,ASP.NET 就無法判斷該值是否已變更。如果該屬性是在程式碼中存取,則屬性值就會寫入資料存放區。
注意事項: 在所有情況下,此決策會套用至特定提供者的所有設定檔屬性。
如果您要使用非內建的屬性型別,在每個頁面要求結尾撰寫設定檔資料會耗費一些時間。您可以採用下列方式減輕這個額外負荷:
在設定檔中僅使用內建型別。
將 <profile> 組態項目中的 automaticSaveEnabled 屬性設定為 Off,並改為撰寫自訂程式碼,以便偵測變更並在必要時儲存屬性值。
請撰寫自訂程式碼來處理 ProfileAutoSaving 事件,並在事件程式碼中,判斷設定檔屬性是否發生任何變更。如果沒有變更任何屬性,請取消自動儲存作業並將事件的 ContinueWithProfileAutoSave 屬性設定為 false。
工作階段狀態
在使用任何跨處理序 (Out-Of-Process) 工作階段狀態模式時,效能是一個考量事項 (如需詳細資訊,請參閱工作階段狀態模式)。這個章節會提供最佳化工作階段狀態效能的相關資訊。
減少工作階段狀態讀取和寫入的額外負荷
根據預設,每次載入頁面期間,就會載入工作階段狀態資訊。@ Page 指示詞中的 EnableSessionState 屬性會可讓您使用下列設定控制載入工作階段狀態:
True:每次載入頁面時,就會讀取工作階段狀態資料,而且如果資料已變更,就會加以儲存。ASP.NET 可以判斷整數和字串等內建型別是否已變更。如果所有工作階段狀態值都是內建型別且尚未變更,就不會儲存工作階段。如果有任何值不是內建型別,而且已存取任何非內建的工作階段值,就會儲存所有工作階段狀態資訊。這是由於 ASP.NET 不會追蹤非內建的型別是否已變更,所以最安全的決定就是儲存所有資料。
False:載入頁面時,不會讀取工作階段狀態資料。
ReadOnly:每次載入頁面時,就會讀取工作階段狀態資料,不過即使程式碼中對工作階段狀態值進行變更,也不會儲存資料。
避免工作階段狀態的鎖定爭用
請避免在需要工作階段狀態的頁面上使用 <IFRAME> 項目。如果以相同的工作階段狀態識別項對 ASP.NET 進行多重要求,而且這些要求都是針對 EnableSessionState 設定為 true 的 ASP.NET 網頁發出時,平行要求將會彼此爭用與跨處理序工作階段狀態相關聯的鎖定。如果是 <IFRAME> 項目的情況,這就表示頁面上顯示於多重 <IFRAME> 項目中的 ASP.NET 網頁可能會爭用相同的工作階段狀態。結果就是每個個別的要求將會在伺服器上序列化。
Web 組件個人化
當頁面執行時,就會載入 ASP.NET 個人化資訊。為了判斷任何 Web 組件個人化資訊是否已變更,ASP.NET 會呼叫 Equals 方法來比較使用 PersonalizableAttribute 屬性標記的舊和新屬性值。
如果任何個人化屬性值已變更,就會儲存個人化資料。若為整數等內建型別,Equals 方法就會直接比較舊和新屬性值。不過,若為非內建型別,ASP.NET 就會比較參考的值,但不一定是型別執行個體 (Instance) 所維護的資料。
例如,若為 ArrayList 型別的屬性,Equals 方法就會比較 ArrayList 參考的舊和新值,但不會比較 ArrayList 物件的內容。如果 ArrayList 參考尚未變更,即使清單中加入新的項目,Equals 方法也會傳回 true。在這種情況下,就不會儲存 ArrayList 資料。
非內建型別的這個演算法很有效率,不過在不儲存資料方面會發生錯誤。如果您想要儲存非內建型別的資料 (例如 ArrayList 物件),請將 IsDirty 屬性設定為 true (如果控制項衍生自 WebPart 的話),或呼叫採用控制項做為參數的 SetPersonalizationDirty 方法。
站台巡覽
相較於小型的網站導覽,大型的網站導覽會降低效能。例如,在測試案例中,將節點數目從 100 增加至 1000 (增加十倍) 可能會增加頁面載入時間約三分之一。
安全性調整 (根據角色篩選節點) 會比增加節點數目造成更大的負面效能影響。例如,具有 1000 個節點之網站導覽的處理負荷是具有 100 個節點之網站導覽的 10 倍。
減輕這項影響的部分建議事項包括:
開啟安全性調整時,建議的最大節點數目為 150。
請在網站導覽的每個節點中設定 Roles 屬性。如果這個 roles 屬性存在,只要使用者屬於屬性中所列的其中一個角色,ASP.NET 就可以略過與 SiteMapNode 相關聯之 URL 的 URL 和檔案授權。不過,請注意,如果使用者不屬於任何指定的角色,則 ASP.NET 將會回到速度較慢的檔案和 URL 授權檢查。
請建立繼承自 SiteMapProvider 類別的類別,並覆寫 IsAccessibleToUser 方法,以便僅檢查網站導覽每個節點中的 Roles 屬性。這會樣加速篩選程序,因為它會略過 URL 和檔案授權。不過,這個方法需要 Web 應用程式中的兩個平行安全性定義。第一個定義是 Web.config 檔中的授權資訊 (以及如果啟用 Windows 驗證時,檔案授權的 NTFS 存取控制清單)。第二個定義是網站導覽中的角色資訊。您應該根據網站導覽處理中的效能改善,權衡分割安全性資訊的安全性管理負荷。
如需詳細資訊,請參閱 ASP.NET 網站導覽安全性調整和 ASP.NET 授權。