跟蹤網站日志的時候發現了這個異常,如下是異常的詳細信息:
錯誤信息:The client disconnected. 2009-4-6 19:35:41
at System.Web.UI.ViewStateException.ThrowError(Exception inner, String persistedState, String errorPageMessage, Boolean macValidationError)
at System.Web.UI.HiddenFieldPageStatePersister.Load()
at System.Web.UI.Page.LoadPageStateFromPersistenceMedium()
at SpringStudio.Naming.Website.PageBase.LoadPageStateFromPersistenceMedium()
at System.Web.UI.Page.LoadAllState()
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
看看StackTrace就知道,這個錯誤是由於ViewState引發的。ViewState是個讓人即愛又恨的東西。說 是愛吧,是因為用起來很方便,控件的狀態能自動維持。說是恨吧,原因是其性能不是太高,尤其是頁面 較大的時候。不知道當初微軟在設計.NET的時候為什麼的引入ViewState機制,我研究過一些用.NET開發 的網站,很多網站都是直接禁用了ViewState。原因很簡單,一個稍微大一點的頁面,產生的ViewState簡 直讓人受不了,這麼大的ViewState將對網絡帶寬帶來極大的壓力。同時,對系統性能也會造成一定的影 響,因為為了能把數據存儲在網頁中,系統必須對各種對象做串行化處理,最後編碼為Base64的字符串存 儲在網頁中的隱藏字段中(一般默認是存儲在名為__VIEWSTATE的隱藏Field中)。當網頁被Post到服務器 的時候,服務器又將對裡面的數據做反串行化處理,在反串行化之前還得驗證數據的完整性和正確性。上 面這個錯誤,就是因為在反串行化的過程中,由於客戶端浏覽器未能完整的Post保存在ViewState中的數 據而引發的異常。如果用戶所在的網絡情況不是很好,Post一個表單需要較長的時間,用戶在等待的時候 點擊了“停止”按鈕,或者干脆轉向了其他頁面,這個時候,客服端單方面中斷了網絡鏈接,即所謂的“ The client disconnected”,導致回發的ViewState不完整而引發了此異常。一般情況下,這個異常對於 服務器和用戶體驗都不會帶來太大的影響,故服務器在捕獲到這個異常的時候可以忽略它。
即便我們可以忽略這個異常,但有幾點還是值得注意和思考:
1. 頁面中不需要的ViewState的控件,盡量將其EnableViewState設置為False,這樣可以大大降低網 頁的ViewState。如果你的頁面更本不需要使用ViewState,則干脆從頁面級,甚至是整個站點級(在 Web.config中設置)禁止ViewState,這樣就能有效防止該異常的發生,同時提高系統性能。
2. ViewState從設計上來說是個好東西,但苦於網站的帶寬和服務器資源總是有限的,所以在設計網 站的時候,就得盡量少用ViewState。等什麼時候,我們的網絡帶寬足夠大,並且Server足夠Powerful的 時候,這個問題就可以忽略了。
3. 如果非要使用ViewState,有兩種方法可以減少ViewState的大小。第一,啟用壓縮技術。在 ViewState被發送到客戶端之前,調用壓縮算法將其壓縮。根據我的經驗,就是一般的zip壓縮,壓縮率也 在30-50%之間,有的甚至更高,這取決於具體的數據。當數據回發的時候,先將其做解壓縮處理,然後在 執行其他的ViewState操作。第二,將ViewState存儲在服務器的硬盤上面,道理一樣,在發送到客戶端之 前,將數據以文件的形式保存在服務器的硬盤上。這裡需要注意的是文件名必須的唯一,原因就不多說了 。當頁面回發的時候,直接根據文件名從硬盤上加載ViewState即可。這兩種方式的實現都很簡單,重寫 頁面的如下兩個事件即可:
protected override void SavePageStateToPersistenceMedium(object viewState)
{
// 壓縮ViewState或者存到到硬盤上
}
protected override object LoadPageStateFromPersistenceMedium()
{
// 解壓ViewState或者從硬盤加載數據
}
上面談到的兩種方法都有其局限性,第一種方法節約了網絡帶寬,犧牲了CUP計算時間,因為壓縮算法 還是比較費CPU時間的。第二種方法,極大的節約了網絡帶寬,但也極大的增加了I/O的負荷。具體用那種 方法,只能具體問題具體分析了,不能一概而論。
4. 如果本身網頁的ViewState不是很大,網站卻經常拋出這個異常,則至少可以說明你的網站速度太 慢了,用戶在提交表單的時候需要花費一個較長的等待時間。這種情況,就得考慮為你的網站做帶寬和硬 件上的升級了。
好,就到這裡吧。歡迎就此問題展開深入討論。