視圖狀態

視圖狀態是 ASP.NET 頁框架用於在往返過程之間保留頁和控制項值的方法。在呈現頁的 HTML 標記時,必須在回發過程中保留的頁和值的當前狀態將被序列化為 Base64 編碼字元串。然後,此信息將被放入到一個或多個視圖狀態隱藏欄位中。

基本介紹

  • 中文名:視圖狀態
  • 外文名:view state
  • 功能:ASP.NET 頁中的存儲庫
  • 適用於:編程
簡介,方案,功能,背景,注意事項,控制項狀態,狀態保存,狀態取值,安全保證,

簡介

ASP.NET 視圖狀態概述 .NET Framework 4
本主題包含以下各節:
方案
功能
背景
類參考

方案

視圖狀態由 ASP.NET 頁框架自動用於保存在各個回發之間必須保留的信息。此信息包括控制項的任何非默認值。
您還可以使用視圖狀態來存儲特定於頁的應用程式數據。

功能

視圖狀態是 ASP.NET 頁中的存儲庫,可以存儲必須在回發過程中保留的值。頁框架使用視圖狀態在各個回發之間保存控制項設定。
可以在您自己的應用程式中使用視圖狀態完成以下工作:
在各個回發之間保存值,而不將這些值存儲在會話狀態或用戶配置檔案中。
存儲您定義的頁或控制項屬性的值。
創建一個自定義視圖狀態提供程式,以便將視圖狀態信息存儲在 SQL Server 資料庫或其他數據存儲區中。
例如,您可以將信息存儲在視圖狀態中,這樣在下次將該頁傳送到伺服器時,代碼便可以在頁載入事件過程中訪問這些信息。

背景

Web 應用程式是無狀態的。每次從伺服器請求頁時,都會創建網頁類的一個新實例。這通常意味著在每次往返過程中會丟失該頁及其控制項中的所有信息。例如,默認狀態下,如果用戶將信息輸入到 HTML 網頁上的文本框中,該信息會傳送到伺服器。但是,該信息不會在回響中返回到瀏覽器。
為了克服 Web 編程的這一固有的局限性,ASP.NET 頁框架包含幾種狀態管理功能,可以在往返過程之間將頁和控制項值保存到 Web 伺服器。其中一種功能便是視圖狀態。
默認情況下,ASP.NET 頁框架使用視圖狀態在往返過程之間保存頁和控制項值。在呈現頁的 HTML 時,必須在回發過程中保留的頁和值的當前狀態將被序列化為 Base64 編碼字元串。然後,它們將被放入頁中的一個或多個隱藏欄位。
您可以在代碼中使用頁的 ViewState屬性訪問視圖狀態。ViewState屬性是一個包含鍵/值對(其中包含視圖狀態數據)的字典。
安全說明
惡意用戶可以很容易地查看和修改隱藏域的內容。有關如何保護視圖狀態數據的更多信息,請參見本主題後面部分中的保護視圖狀態。
通過實現自定義的 PageStatePersister類以存儲頁數據,您可以更改默認行為並將視圖狀態存儲到另一個位置(如 SQL Server 資料庫)。有關將頁狀態存儲在流中而不是隱藏欄位中的示例,請參見 PageStatePersister類的示例。

注意事項

視圖狀態提供了特定 ASP.NET 頁的狀態信息。如果需要在多個頁上使用信息,或者需要在對網站的多次訪問之間保存信息,必須使用其他方法來維護狀態。
視圖狀態信息被序列化為 XML,然後使用 base-64 編碼機制進行編碼,這可能會生成大量數據。將頁傳送到伺服器時,視圖狀態的內容會作為頁回發信息的一部分進行傳送。如果視圖狀態包含大量信息,則會影響頁的性能。請使用應用程式的典型數據測試頁性能,以確定視圖狀態的大小是否會導致性能問題。
另一個注意事項是,如果隱藏欄位中的數據量過大,則某些代理和防火牆將禁止訪問包含這些數據的頁。由於最大允許數量可能隨所實現的防火牆和代理的不同而不同,因此大的隱藏欄位可能會導致間歇性問題。如果存儲在 ViewState屬性中的數據量超出了在頁的 MaxPageStateFieldLength屬性中指定的值,則頁會將視圖狀態拆分為多個隱藏欄位。這可減小單個隱藏欄位的大小,使其大小不會超過防火牆所允許的上限。
在默認情況下,將啟用視圖狀態,但頁上的某些控制項可能不需要視圖狀態。例如,如果某個控制項在每次回發時都會從數據存儲區進行刷新,則可以關閉該控制項的視圖狀態以減少視圖狀態的大小。
您可以對控制項進行配置,以便默認情況下禁用頁或容器控制項中所有控制項的視圖狀態,然後可以為特定控制項啟用視圖狀態。您還可以對控制項進行配置,以便禁用視圖狀態並且無法為子控制項啟用視圖狀態。
若要在默認情況下禁用控制項的視圖狀態,以便可以為子控制項啟用視圖狀態,請將控制項的 ViewStateMode屬性設定為 Disabled。若要在默認情況下禁用整頁的視圖狀態,請將 @ Page指令的 ViewStateMode特性設定為 Disabled。
若要禁用控制項及其子控制項的視圖狀態,以便無法為子控制項啟用視圖狀態,請將控制項的 EnableViewState屬性設定為 false。若要禁用整頁及其所有子控制項的視圖狀態,請將 @ Page指令的 EnableViewState特性設定為 false。
注意
即使您明確關閉了視圖狀態,仍會將隱藏欄位傳送到瀏覽器,以指示針對該頁進行回發。
某些移動設備根本不允許使用隱藏欄位。

控制項狀態

除視圖狀態以外,ASP.NET 還支持控制項狀態。頁使用控制項狀態來保留必須在回發之間保留的控制項信息,即使已為頁或某個控制項禁用視圖狀態也是如此。控制項狀態與視圖狀態類似,也存儲在一個或多個隱藏欄位中。

狀態保存

您可以使用頁的 ViewState屬性(該屬性公開一個字典對象)來訪問視圖狀態信息。可以使用此字典存儲自定義值。一個典型用法是存儲您在頁中定義的自定義屬性的值。
由於視圖狀態是作為隱藏欄位傳送的,因此直到該頁的 PreRenderComplete事件發生之前,都可以對視圖狀態進行更改。在將頁呈現到瀏覽器之後,便無法保存對視圖狀態所做的更改。
如果用戶查看網頁的源並可以對 base-64 編碼字元串進行解碼,則可以看到隱藏視圖狀態欄位中的信息。這可能會產生安全問題。
注意
若要使用 ViewState屬性,ASP.NET 網頁必須有一個具有 runat="server"特性的 form元素。
若要將值保存到視圖狀態,請創建一個包含要保存的值的新項,並將該項添加到視圖狀態字典中。下面的示例演示一個 ASP.NET 網頁,該網頁包含用於將一個字元串和一個整數值保存在視圖狀態中的代碼。
C#
VB
<%@ Page Language="C#"%> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server"> // Sample ArrayList for the page.ArrayList PageArrayList; ArrayList CreateArray() { // Create a sample ArrayList.ArrayList result = newArrayList(4); result.Add("item 1"); result.Add("item 2"); result.Add("item 3"); result.Add("item 4"); returnresult; } voidPage_Load(objectsender, EventArgs e) { if(ViewState["arrayListInViewState"] != null) { PageArrayList = (ArrayList)ViewState["arrayListInViewState"]; } else{ // ArrayList isn't in view state, so it must be created and populated.PageArrayList = CreateArray(); } // Code that uses PageArrayList.} voidPage_PreRender(objectsender, EventArgs e) { // Save PageArrayList before the page is rendered.ViewState.Add("arrayListInViewState", PageArrayList); } </script> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>View state sample</title> </head> <body> <form id="form1"runat="server"> <div> </div> </form> </body> </html>
可以存儲在視圖狀態中的數據類型 您可以將下列類型的對象存儲到視圖狀態中:
字元串
整數
Boolean值
Array對象
ArrayList對象
自定義類型轉換器(有關更多信息,請參見 TypeConverter類)
您還可以存儲其他類型的數據,但是必須使用 Serializable特性編譯類,以便可以為視圖狀態序列化該類的值。

狀態取值

若要從視圖狀態讀取值,請獲取頁的 ViewState屬性,然後從視圖狀態字典中讀取該值。
下面的示例演示如何從視圖狀態中獲取一個名為 arrayListInViewState的 ArrayList對象,然後將一個 GridView控制項作為數據源綁定到該對象。
arrayList = newArrayList(); arrayList = (ArrayList)ViewState["arrayListInViewState"]; this.GridView1.DataSource = arrayList; this.GridView1.DataBind();
視圖狀態中的值被類型化為 String。在 Visual Basic 中,如果設定了 Option Strict On,則必須在使用視圖狀態值之前將這些值強制轉換為適當的類型,如上面的示例中所示。在 C# 中,當您讀取視圖狀態值時,必須始終將其強制轉換為適當的類型。
如果嘗試從不存在的視圖狀態中獲取值,則不會引發任何異常。若要確保值在視圖狀態中,請首先檢查對象是否存在。下面的示例演示如何檢查視圖狀態項。
if(ViewState["color"] == null) // No such value in view state, take appropriate action.
如果您嘗試通過其他某種方式使用不存在的視圖狀態項(如檢查其類型),則會引發 NullReferenceException異常。

安全保證

默認情況下,視圖狀態數據存儲在頁上的隱藏欄位中,並使用 Base64 編碼機制進行編碼。此外,還會使用計算機身份驗證代碼 (MAC) 密鑰從視圖狀態數據中創建這些數據的哈希。哈希值會添加到編碼的視圖狀態數據中,並且生成的字元串會存儲在頁中。當頁被回發到伺服器時,ASP.NET 頁框架會重新計算哈希值,並將其與視圖狀態中存儲的值進行比較。如果哈希值不匹配,將引發異常,指示視圖狀態數據可能無效。
通過創建哈希值,ASP.NET 頁框架可以測試視圖狀態數據是否已被損壞或篡改。但是,即使視圖狀態數據未被篡改,這些數據仍然可能被惡意用戶截獲和讀取。
使用 MAC 計算視圖狀態哈希值 用於計算視圖狀態哈希值的 MAC 密鑰既可以自動生成,也可以在 Machine.config 檔案中指定。如果該密鑰是自動生成的,則基於計算機的 MAC 地址(它是該計算機中網路適配器的唯一 GUID 值)進行創建。
惡意用戶很難根據視圖狀態中的哈希值進行反向工程處理以推斷出 MAC 密鑰。因此,MAC 編碼是一種用來確定視圖狀態數據是否已更改的相當可靠的方式。
通常,用於生成哈希的 MAC 密鑰越大,不同字元串的哈希值相同的可能性就越小。如果密鑰是自動生成的,則 ASP.NET 使用 SHA-1 編碼來創建一個大型密鑰。不過,在網路場環境中,所有伺服器的密鑰必須相同。如果密鑰不同,那么當頁回發至創建該頁的伺服器之外的其他伺服器時,ASP.NET 頁框架將引發異常。因此,在網路場環境中,應在 Machine.config 檔案中指定密鑰,而不是讓 ASP.NET 自動生成密鑰。在這種情況下,請確保您創建的密鑰足夠長,以便使哈希值具有充分的安全性。但是,密鑰越長,創建哈希所需要的時間也就越多。因此,必須在安全需求與性能需求之間進行權衡。
加密視圖狀態 雖然 MAC 編碼有助於防止篡改視圖狀態數據,但它無法阻止用戶查看數據。可以通過下面兩種方式來防止他人查看此數據:通過 SSL 傳輸頁,以及對視圖狀態數據進行加密。要求通過 SSL 傳送頁有助於防止那些原本不應該收到該頁的人探查數據包和未經授權訪問數據。
但是,請求該頁的用戶仍然能夠查看視圖狀態數據,因為 SSL 會解密該頁以便在瀏覽器中顯示它。如果您不擔心授權用戶可以訪問視圖狀態數據,則這種方法很好。但在某些情況下,控制項可能會使用視圖狀態存儲任何用戶都不應訪問的信息。例如,頁可能包含一個數據綁定控制項,該控制項存儲視圖狀態的項標識符(數據密鑰)。如果這些標識符中包含敏感數據(如客戶 ID),則應對視圖狀態數據進行加密來替代通過 SSL 傳送頁,或是將其作為通過 SSL 傳送頁的補充方法。
若要加密數據,請將頁的 ViewStateEncryptionMode屬性設定為 true。在視圖狀態中存儲信息時,可以使用常規的讀寫技術;頁會為您處理所有加密和解密工作。對視圖狀態數據進行加密可能會影回響用程式的性能。因此,如不需要,請不要使用加密。
控制項狀態加密 使用控制項狀態的控制項可以通過調用 RegisterRequiresViewStateEncryption方法來要求對視圖狀態進行加密。如果頁中的任何控制項都要求對視圖狀態進行加密,則該頁中的所有視圖狀態都會進行加密。
基於每個用戶的視圖狀態編碼 如果網站需要對用戶進行身份驗證,則可以設定 Page_Init事件處理程式中的 ViewStateUserKey屬性,以便將頁的視圖狀態與特定用戶相關聯。這將有助於防止一鍵式 (one-click) 攻擊,在這種方式的攻擊中,惡意用戶創建一個有效的預先填充的網頁,該網頁具有來自以前創建的網頁的視圖狀態。攻擊者隨後引誘受害者單擊一個連結,該連結使用受害者的標識向伺服器傳送頁。
如果設定了 ViewStateUserKey屬性,將使用攻擊者的標識來創建原始頁的視圖狀態的哈希。受害者被引誘重新傳送此頁時,由於用戶密鑰不同,因此哈希值也將不同。這樣,頁的驗證將失敗,並且引發一個異常。
必須將 ViewStateUserKey屬性與每個用戶的一個唯一值(如用戶名或標識符)相關聯。
在共享承載環境中保護配置的安全性 在共享的承載環境中,惡意用戶可能會修改狀態管理屬性,從而可能影響到計算機上的其他應用程式。修改方式包括:直接修改 Machine.config;使用配置類進行修改;以及使用其他管理和配置工具進行修改。您可以通過對配置檔案的節進行加密來幫助防止他人修改您的應用程式配置。
類參考
ViewState
提供一個字典對象,以便在對同一頁的多個請求之間保留值。
PageStatePersister
提供一種方式,用於為存儲(如在 SQL Server 資料庫中)視圖狀態信息而定義一種自定義機制。

相關詞條

熱門詞條

聯絡我們