asp.net ViewState 是一種新的狀態服務,可供開發人員基於每個使用者來跟蹤 UI 狀態,該輔助資料被儲存在一個名為 __VIEWSTATE 的隱藏欄位中。
當然, ViewState 在 ASP.NET 中有個重要的角色。如果使用恰當,它能夠簡化頁面開發,改進使用者與網站的互動。如果置之不理,它能夠顯著增加網站響應大小,在連線速度慢的情況下,使您的回應時間更加緩慢。因為瀏覽器的每次回傳都會導致ViewState 逐漸增加您的頁面大小,從而導致效能問題。因此,ASP.NET 2.0 的發布帶來了 ViewState 機制的一些改進,這使得 ViewState 使用更簡單,又不會防礙網站效能。這些改進包括:減少編碼數量,採用控制項狀態從內容中分離出行為狀態,以及智能整合資料繫結控制項。你可以在不需要維護控制項狀態的情況下通過停用控制項(EnableViewState = false )解決這個問題。 然而,很多情況下保持控制項的狀態是必需的,壓縮的ViewState有助於提高效能。
方法一:使用System.IO.Compression
System.IO.Compression 命名空間包含提供基本的流壓縮和解壓縮服務的類。
此命名空間包含2個類分別為:
DeflateStream 提供用於使用 Deflate 演算法壓縮和解壓縮流的方法和屬性。
GZipStream 提供用於壓縮和解壓縮流的方法和屬性。
在下面的示範代碼中,我們建立一個ViewStateCompression類,包含2個方法,並都返回byte[]資料:
1.GZipStream版的壓縮/解壓縮
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.IO;using System.IO.Compression;/// <summary>///ViewStateCompression 的摘要說明/// </summary>public class ViewStateCompression{ public ViewStateCompression() { // //TODO: 在此處添加建構函式邏輯 // } // 壓縮 public static byte[] Compress(byte[] data) { MemoryStream output = new MemoryStream(); GZipStream gzip = new GZipStream(output, CompressionMode.Compress, true); gzip.Write(data, 0, data.Length); gzip.Close(); return output.ToArray(); } // 解壓縮 public static byte[] Decompress(byte[] data) { MemoryStream input = new MemoryStream(); input.Write(data, 0, data.Length); input.Position = 0; GZipStream gzip = new GZipStream(input, CompressionMode.Decompress, true); MemoryStream output = new MemoryStream(); byte[] buff = new byte[64]; int read = -1; read = gzip.Read(buff, 0, buff.Length); while (read > 0) { output.Write(buff, 0, read); read = gzip.Read(buff, 0, buff.Length); } gzip.Close(); return output.ToArray(); }}
2.執行ViewStateCompression類
想使用ViewStateCompression的壓縮和解壓頁面ViewState的功能,我們必須重寫 System.Web.UI.Page 的 SavePageStateToPersistenceMedium() 和LoadPageStateFromPersistenceMedium() 方法。
SavePageStateToPersistenceMedium 方法 可以還原序列化的ViewState,它接受一個 ViewState對象的參數。
LoadPageStateFromPersistenceMedium 方法 可以序列化ViewState,它接受一個Base64編碼的字串參數。
重寫代碼如下,建立了一個繼承與System.Web.UI.Page的BasePage類:
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.IO;using System.Web.UI;/// <summary>///BasePage 的摘要說明/// </summary>public class BasePage : System.Web.UI.Page{ public BasePage() { // //TODO: 在此處添加建構函式邏輯 // } protected override void SavePageStateToPersistenceMedium(object pageViewState) { LosFormatter losformatter = new LosFormatter(); StringWriter sw = new StringWriter(); losformatter.Serialize(sw, pageViewState); string viewStateString = sw.ToString(); byte[] b = Convert.FromBase64String(viewStateString); b = ViewStateCompression.Compress(b); // ----ClientScript.RegisterHiddenField("__ZIPSTATE", Convert.ToBase64String(b)); // // 相容ASP.NET Ajax 的ViewState壓縮 ScriptManager.RegisterHiddenField(this, "__ZIPSTATE", Convert.ToBase64String(b)); } // 序列化ViewState protected override object LoadPageStateFromPersistenceMedium() { string custState = Request.Form["__ZIPSTATE"]; byte[] b = Convert.FromBase64String(custState); b = ViewStateCompression.Decompress(b); LosFormatter losformatter = new LosFormatter(); return losformatter.Deserialize(Convert.ToBase64String(b)); }}
經過上述的方法後,你的ViewState可能會減少30-40%.
3.ViewState SEO
ViewState會影響SEO,當然,影響並不是很大。搜尋引擎在搜錄頁面的時候,從頁面源檔案第一個字元開始,到100K的位置,後面的收錄不是很友好,甚至還會出現收錄問題。因此,在前100K的時候,我們可以考慮將ViewState 移到頁面的底部, 之前。參考代碼請下載本文的樣本,這裡給出參考:
移動之前:
移動後:
方法二:使用session完全刪除ViewState
使用這個方法即可以完全刪除ViewState,又可以完全儲存ViewState的優勢,還可以減少用戶端要求下載的多餘位元組,還可以搜尋引擎解決收錄問題。原理是通過利用Session允許在伺服器上儲存ViewState的方法重寫上面的SavePageStateToPersistenceMedium() 和LoadPageStateFromPersistenceMedium() 方法。
改寫上面的方法後的代碼如下:
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.IO;using System.Web.UI;/// <summary>///BasePage 的摘要說明/// </summary>public class BasePage:System.Web.UI.Page{ public BasePage() { // //TODO: 在此處添加建構函式邏輯 // } protected override void SavePageStateToPersistenceMedium(object pageViewState) { MemoryStream ms = new MemoryStream(); LosFormatter m_formatter = new LosFormatter(); m_formatter.Serialize(ms, pageViewState); ms.Position = 0; StreamReader sr = new StreamReader(ms); string viewStateString = sr.ReadToEnd(); byte[] ViewStateBytes = Convert.FromBase64String(viewStateString); ViewStateBytes = ViewStateCompression.Compress(ViewStateBytes); Session["ViewState"] = Convert.ToBase64String(ViewStateBytes); ms.Close(); return; } // 序列化ViewState protected override object LoadPageStateFromPersistenceMedium() { object viewStateBag; string m_viewState = (string)Session["ViewState"]; byte[] ViewStateBytes = Convert.FromBase64String(m_viewState); ViewStateBytes = ViewStateCompression.Decompress(ViewStateBytes); LosFormatter m_formatter = new LosFormatter(); try { viewStateBag = m_formatter.Deserialize(Convert.ToBase64String(ViewStateBytes)); } catch (Exception ex) { //Log.Insert( "頁面Viewtate是空。" ); viewStateBag = string.Empty; } return viewStateBag; }}
改寫後我們可以從看到ViewState完全被刪除了,而且傳輸到用戶端的資料從1006B 減少 到750B,這在頁面中很多資料來源控制項時,將提高了一定效能: