ASP.NET 檢視狀態概觀
更新:2007 年 11 月
檢視狀態是一種方法,供 ASP.NET 網頁架構用來保留來回存取之間網頁和控制項的值。轉譯網頁的 HTML 標記時,在回傳期間必須保留的頁面目前狀態和值都會序列化成 base64 編碼的字串。然後這項資訊就會放入檢視狀態的一個或多個隱藏欄位中。
這個主題包含:
案例
ViewState 功能
背景
類別參考
其他資源
新功能
案例
ASP.NET 網頁架構會自動使用檢視狀態,以維持必須保留在回傳之間的資訊。這項資訊包括控制項的任何非預設值。
您也可以使用檢視狀態,以儲存頁面專用的應用程式資料。
回到頁首
功能
檢視狀態是 ASP.NET 網頁中的儲存機制,可以儲存回傳期間需要保留的值。網頁架構會使用檢視狀態,以維持回傳之間的控制項設定。
您可以在自己的應用程式中使用檢視狀態,執行下列動作:
將值維持在回傳之間,而不儲存至工作階段狀態或使用者設定檔。
儲存您所定義的頁面值或控制項屬性。
建立自訂檢視狀態提供者,讓您將檢視狀態資訊儲存在 SQL Server 資料庫或其他資料存放區中。
例如,您可以將資訊儲存在檢視狀態中,在下次將網頁傳送至伺服器時,程式碼可以在網頁載入事件期間存取檢視狀態。如需使用上的建議,請參閱 ASP.NET 狀態管理建議事項。
回到頁首
背景
Web 應用程式沒有狀態 (Stateless)。每次伺服器要求網頁時,都會建立 Web 網頁類別的新執行個體。這通常表示在每次來回存取時,網頁的所有資訊及其控制項都會遺失。例如,根據預設,當使用者在 HTML Web 網頁的文字方塊中輸入資訊時,這項資訊就會傳送至伺服器。但是伺服器在回應時,卻不會將這項資訊傳回瀏覽器。
為了克服這個 Web 程式設計的固有限制,ASP.NET 網頁架構會包括數個狀態管理功能,以保留來回存取 Web 伺服器之間網頁和控制項的值。其中一個功能為檢視狀態。如需詳細資訊,請參閱 ASP.NET 狀態管理概觀。
根據預設,ASP.NET 網頁架構會使用檢視狀態,以保留來回存取之間的頁面和控制項值。轉譯網頁的 HTML 時,在回傳期間必須保留的頁面目前狀態和值都會序列化成 base64 編碼的字串。然後這些字串就會放入頁面的一個或多個隱藏欄位中。
您可以使用頁面的 ViewState 屬性,存取程式碼中的檢視狀態。ViewState 屬性是包含索引鍵/值組的字典,該索引鍵/值組包含檢視狀態資料。
安全性注意事項: |
---|
惡意使用者很輕易就能看見並修改隱藏欄位的內容。如需如何確保檢視狀態資料安全的詳細資訊,請參閱本主題稍後提及的設定檢視狀態的安全性。 |
如需在檢視狀態中儲存資訊時機的建議,請參閱 ASP.NET 狀態管理建議事項。
藉由實作自訂 PageStatePersister 類別以儲存網頁資料,您可以變更預設行為並在其他位置 (例如,SQL Server 資料庫) 儲存檢視狀態。如需將頁面狀態儲存在資料流 (而非隱藏欄位) 中的範例,請參閱 PageStatePersister 類別的範例。
檢視狀態的使用考量
檢視狀態為特定 ASP.NET Web 網頁提供狀態資訊。如果您必須在多個網頁上使用資訊,或必須在造訪網站後仍然保留資訊,就必須應使用其他方法維護狀態。您可以使用應用程式狀態、工作階段狀態或設定檔屬性。
檢視狀態資訊會序列化為 XML,然後使用 base64 編碼進行編碼,而這麼做便會產生大量的資料。當網頁傳送至伺服器時,會將檢視狀態的內容做為網頁回傳資訊的一部分傳送。如果檢視狀態包含大量資訊,則其可以影響網頁的效能。您可以針對自己的應用程式使用一般資料來測試網頁的效能,以判斷檢視狀態的大小是否會造成應用程式的效能問題。如需使用檢視狀態的替換選項,請參閱 ASP.NET 狀態管理建議事項。
如果您不需儲存個別控制項的控制項資訊,可以停用控制項的檢視狀態。如果頁面上的控制項在每一次回傳時就從資料存放區重新整理,您便可以關閉該控制項的檢視狀態,以減少檢視狀態的大小。例如,您可以關閉控制項 (例如 GridView 控制項) 的檢視狀態。
注意事項: |
---|
即使您明確關閉檢視狀態,仍會將隱藏欄位傳送至瀏覽器,以指示該網頁發生回傳。 |
另一個考量是,如果隱藏欄位中的資料量變得很大,某些 Proxy 和防火牆會防止包含這些資料的網頁存取。因為允許的最大資料量可能會因不同的防火牆和 Proxy 實作而有所不同,所以大型隱藏欄位會產生斷斷續續的問題。如果儲存在 ViewState 屬性中的資料量超過頁面的 MaxPageStateFieldLength 屬性所指定的值,則該頁面會將檢視狀態分割為多個隱藏的欄位。這麼做能減少個別隱藏欄位的大小,使其低於防火牆會拒絕的大小。
某些行動裝置完全不允許隱藏欄位。因此,檢視狀態將不會在這些裝置上運作。如需詳細資訊和替代方案,請參閱 ASP.NET Mobile Web 開發概觀。
控制項狀態
除了檢視狀態之外,ASP.NET 還支援控制項狀態。即使已停用網頁或控制項的檢視狀態,網頁也會使用控制項狀態,以保存必須在回傳之間保留的控制項資訊。控制項狀態和檢視狀態一樣,都是儲存在一個或多個隱藏欄位中。
將值儲存在檢視狀態中
您可以使用會公開字典物件之頁面的 ViewState 屬性,存取檢視狀態資訊。您可以使用這個字典來儲存自訂值。這個字典一般是用來儲存您在頁面中定義的自訂屬性值。
因為檢視狀態是以隱藏欄位傳送,所以直到頁面的 PreRenderComplete 事件發生之前,您都可以對檢視狀態進行變更。當頁面轉譯至瀏覽器之後,將不會儲存對檢視狀態所做的變更。
如果使用者檢視網頁的原始檔,而且可以將已經過 base64 編碼的字串解碼,就可以看到隱藏的檢視狀態欄位中的資訊。如此便會造成潛在的安全性問題。如需檢視狀態之安全性問題的詳細資訊,請參閱本主題稍後提及的設定檢視狀態的安全性。
注意事項: |
---|
若要使用 ViewState 屬性,則 ASP.NET 網頁必須具有包含 屬性的 form 項目。 |
若要將值儲存至檢視狀態,請建立內含要儲存之值的新項目,然後將這個項目加入至檢視狀態字典。下列範例示範的 ASP.NET 網頁,其程式碼會將字串和整數值儲存在檢視狀態中。
<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script >
' Sample ArrayList for the page.
Dim PageArrayList As ArrayList
Function CreateArray() As ArrayList
' Create a sample ArrayList.
Dim result As ArrayList
result = New ArrayList(4)
result.Add("item 1")
result.Add("item 2")
result.Add("item 3")
result.Add("item 4")
Return result
End Function
Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
If (Me.ViewState("arrayListInViewState") IsNot Nothing) Then
PageArrayList = CType(Me.ViewState("arrayListInViewState"), ArrayList)
Else
' ArrayList isn't in view state, so it must be created and populated.
PageArrayList = CreateArray()
End If
' Code that uses PageArrayList.
End Sub
Sub Page_PreRender(ByVal sender As Object, ByVal e As EventArgs)
' Save PageArrayList before the page is rendered.
Me.ViewState.Add("arrayListInViewState", PageArrayList)
End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head >
<title>View state sample</title>
</head>
<body>
<form id="form1" >
<div>
</div>
</form>
</body>
</html>
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script >
// Sample ArrayList for the page.
ArrayList PageArrayList;
ArrayList CreateArray()
{
// Create a sample ArrayList.
ArrayList result = new ArrayList(4);
result.Add("item 1");
result.Add("item 2");
result.Add("item 3");
result.Add("item 4");
return result;
}
void Page_Load(object sender, 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.
}
void Page_PreRender(object sender, EventArgs e)
{
// Save PageArrayList before the page is rendered.
ViewState.Add("arrayListInViewState", PageArrayList);
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head >
<title>View state sample</title>
</head>
<body>
<form id="form1" >
<div>
</div>
</form>
</body>
</html>
您可以在檢視狀態中儲存的資料型別
您可以在檢視狀態中儲存下列型別的物件:
字串
整數
Boolean 值
Array 物件
ArrayList 物件
雜湊表
自訂型別轉換子 (Type Converter) (請參閱 TypeConverter 類別以取得詳細資訊)
您也可以儲存其他型別的資料,但是類別必須以 Serializable 屬性編譯,才能將其值序列化供檢視狀態使用。
讀取檢視狀態的值
若要讀取檢視狀態的值,您必須取得網頁的 ViewState 屬性,然後讀取檢視狀態字典中的值。
在下列範例中,會說明如何取得檢視狀態內名為 arrayListInViewState 的 ArrayList 物件,然後將 GridView 控制項繫結至物件做為資料來源。
Dim arrayList As ArrayList
arrayList = CType(ViewState("arrayListInViewState"), ArrayList)
Me.GridView1.DataSource = arrayList
Me.GridView1.DataBind()
arrayList = new ArrayList();
arrayList = (ArrayList)ViewState["arrayListInViewState"];
this.GridView1.DataSource = arrayList;
this.GridView1.DataBind();
檢視狀態中的值是 String 型別。在 Visual Basic 中,如果您設定了 Option Strict On,就必須將檢視狀態值轉換成適當的型別才能使用,如上一個範例所示。在 C# 中,當您讀取檢視狀態值時,一定要轉換成適當的型別。
如果您嘗試從檢視狀態取得不存在的值,則不會擲回任何例外狀況。若要確定值在檢視狀態中,請先查看物件是否存在。下列範例會說明如何查看檢視狀態項目。
If ViewState("color") Is Nothing Then
' No such value in view state, take appropriate action.
End If
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 編碼建立大型金鑰。但是,在 Web 伺服陣列環境中,所有伺服器之間的金鑰都必須相同。如果鍵不相同,且網頁回傳到不是建立該網頁的不同伺服器上時,ASP.NET 網頁架構將會引發例外狀況。因此,在 Web 伺服陣列環境中,您應該在 Machine.config 檔案中指定金鑰,而不是讓 ASP.NET 自動產生金鑰。如果是後者,請確定您所建立的金鑰長度可以提供雜湊值足夠的安全性。但是,金鑰越長,建立雜湊的時間就越久。因此,您必須衡量安全性與效能的需求。
將檢視狀態加密
雖然 MAC 編碼有助於防止竄改檢視狀態資料,但無法防止使用者檢視資料。您可以使用兩種方法來防止人們檢視此資料︰使用 SSL 傳輸網頁和將檢視狀態資料加密。要求頁面透過 SSL 傳送可以有助於防止不應該接收網頁的人們,對網頁進行資料封包探查和未經授權的資料存取。
但是,要求網頁的使用者仍可檢視此檢視狀態資料,因為 SSL 會將網頁解密,以顯示於瀏覽器中。如果您不擔心授權使用者存取檢視狀態資料,就沒有關係。但是在某些情況下,控制項可能會使用檢視狀態,儲存任何使用者都不應該存取的資訊。例如,網頁可能會包含在檢視狀態中儲存項目識別項 (資料金鑰) 的資料繫結控制項。如果這些識別項包含敏感性資料 (例如客戶 ID),則您應該將檢視狀態資料另外加密,或者改為透過 SSL 傳送網頁。
若要加密資料,請將頁面的 ViewStateEncryptionMode 屬性設定為 true。如果您將資訊儲存在檢視狀態中,便可以使用一般讀寫技術,網頁會為您處理所有加密和解密工作。將檢視狀態資料加密會影響應用程式的效能。因此,除非必要否則請勿使用加密。
控制項狀態加密
使用控制項狀態的控制項可以要求透過呼叫 RegisterRequiresViewStateEncryption 方法對檢視狀態進行加密。如果網頁上的任何控制項要求檢視狀態必須加密,則會將網頁上所有檢視狀態都加密。
每位使用者的檢視狀態編碼
如果網站會驗證使用者,您可以設定 Page_Init 事件處理常式中的 ViewStateUserKey 屬性,將頁面的狀態檢視和特定使用者產生關聯。這樣有助於防止按一下的攻擊,這是指惡意使用者建立有效且以先前建立之網頁中檢視狀態先行填滿的 Web 網頁。攻擊者接著會引誘受騙者點選連結,這個連結會使用受騙者的識別 (Identity) 將網頁傳送至伺服器。
設定 ViewStateUserKey 屬性時,攻擊者的識別會用來建立原始網頁之檢視狀態的雜湊。當受騙者被誘使重新傳送網頁時,由於使用者金鑰不同,雜湊值也會不同。網頁的驗證會失敗並擲回例外狀況。
您必須將 ViewStateUserKey 屬性與每位使用者的唯一值產生關聯,例如使用者名稱或識別項。
保護共用集合環境中之設定的安全性
在共用集合環境中,惡意使用者可能可以修改會影響電腦上其他應用程式的狀態管理屬性。只要直接修改 Machine.config 檔案、透過組態類別進行修改,以及透過其他系統管理和組態工具,惡意使用者就能達到上述目的。您可以加密組態檔的區段以防止修改應用程式組態。如需詳細資訊,請參閱使用受保護的組態加密組態資訊。
類別參考
提供字典物件,以保留對相同網頁的多個要求之間的值。 |
|
提供方法以定義儲存檢視狀態資訊的自訂機制,例如儲存在 SQL Server 資料庫中。 |
回到頁首
請參閱
概念
參考
回到頁首