ASP.NET2.0的控制項狀態和檢視狀態探討

來源:互聯網
上載者:User

基本概念

  控制項狀態-為了讓控制項正常工作,有時需要儲存控制項狀態資料。例如,如果編寫了一個自訂控制項,其中具有 顯示不同資訊的不同選項卡,為使該控制項如預期一樣工作,控制項需要知道在往返過程中選擇的是哪個選項卡。ViewState 屬性可用於此目的,但開發人員可能在頁層級關閉了檢視狀態,從而有效地中斷控制項。為解決此問題,ASP.NET 頁架構在 ASP.NET 2.0 版中公開了一種稱為控制項狀態的新功能。 
ControlState 屬性允許保持特定於控制項的屬性資訊,不像 ViewState 屬性一樣可以關閉。若要使用控制項狀態,控制項必須在初始化過程中調用 RegisterRequiresControlState 方法,然後重寫 SaveControlState 和 LoadControlState 方法。

  檢視狀態-檢視狀態是 ASP.NET 頁架構預設情況下用於儲存往返過程之間的頁和控制項值的方法。當呈現頁的 HTML 形式時,需要在回傳過程中保留的頁的目前狀態和值將被序列化為 Base 64 編碼的字串,並輸出到檢視狀態的隱藏欄位中。通過實現自訂的 PageStatePersister 類以儲存頁資料,您可以更改預設行為並將檢視狀態儲存到另一個位置(如 SQL Server 資料庫)。有關將頁狀態儲存到流上而不是隱藏的分頁欄位中的樣本,請參見 檢視狀態持久性機制的樣本。

  您可以通過使用頁的 ViewState 屬性將往返過程中的資料儲存到 Web 服務器來利用自己的代碼訪問檢視狀態。ViewState 屬性是一個包含密鑰/值對(其中包含檢視狀態資料)的字典。

  各自的優勢與劣勢

  檢視狀態

  使用檢視狀態的優點:

  ·不需要任何伺服器資源 檢視狀態包含在頁代碼內的結構中。

  ·實現簡單 檢視狀態無需使用任何自訂編程。預設情況下對控制項啟用狀態資料的維護。

  ·增強安全功能 檢視狀態中的值經過雜湊計算和壓縮,並且針對 Unicode 實現進行編碼,其安全性要高於使用隱藏欄位。 

  使用檢視狀態的缺點

  ·效能注意事項 由於檢視狀態儲存在頁本身,因此如果儲存較大的值,使用者顯示頁和發送頁時的速度可能會減慢。尤其是對行動裝置,其頻寬通常是有限的。

  ·裝置限制 行動裝置可能沒有足夠的記憶體容量來儲存大量的檢視狀態資料。

  ·潛在的安全風險 檢視狀態儲存在頁上的一個或多個隱藏欄位中。雖然檢視狀態以雜湊格式儲存資料,但它可以被篡改。如果直接查看頁輸出源,可以看到隱藏欄位中的資訊,這導致潛在的安全性問題。

  控制項狀態

  使用控制項狀態的優點:

  ·不需要任何伺服器資源 預設情況下,控制項狀態儲存在頁上的隱藏欄位中。 

  ·可靠性 因為控制項狀態不像檢視狀態那樣可以關閉,控制項狀態是管理控制項的狀態的更可靠方法。

  ·通用性 可以編寫自訂配接器來控制如何儲存控制項狀態資料和控制項狀態資料的儲存位置。 

  使用控制項狀態的缺點:

  ·需要一些編程 雖然 ASP.NET 頁架構為控制項狀態提供了基礎,但是控制項狀態是一個自訂的狀態保持機制。為了充分利用控制項狀態,您必須編寫代碼來儲存和載入控制項狀態。

  控制項狀態與檢視狀態樣本

  此樣本示範如何建立一個名為 IndexButton 的自訂控制項,該控制項使用控制項狀態在多個頁請求間維護關鍵狀態資訊。在 ASP.NET 2.0 版中引入的控制項狀態與檢視狀態類似,但功能上獨立於檢視狀態。網頁開發人員可能會出於效能原因而禁用整個頁面或單個控制項的檢視狀態,但他們不能禁用控制項狀 態。控制項狀態是專為儲存控制項的重要資料(如一個頁面控制項的頁數)而設計的,回傳時必須用到這些資料才能使控制項正常工作(即便禁用檢視狀態也不受影響)。默 認情況下,ASP.NET 頁架構將控制項狀態儲存在頁的一個隱藏元素中,檢視狀態也同樣儲存在此隱藏元素中。即使禁用檢視狀態,或是使用 Session 管理狀態時,頁面中的控制項狀態仍會傳輸至用戶端,然後返回到伺服器。在回傳時,ASP.NET 會對隱藏元素的內容進行還原序列化,並將控制項狀態載入到每個註冊過控制項狀態的控制項中。

  此樣本闡釋了一個同時在控制項狀態和檢視狀態中儲存 狀態的自訂控制項。在此樣本中,IndexButton 控制項派生自 Button 類,還定義了一個 Index 屬性,並將該屬性儲存在控制項狀態中。為了進行比較,IndexButton 還定義了一個 IndexInViewState 屬性,該屬性儲存區在 ViewState 字典中。為了瞭解控制項狀態和檢視狀態之間的差異,請使用本文附帶的程式來示範 IndexButton 控制項。

  IndexButton控制項源碼

using System;
using System.ComponentModel;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace CustomerControls
{
 [
  AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal),
  AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal),
  ToolboxData("<{0}:IndexButton runat=\"server\"> </{0}:IndexButton>")
 ]

 public class IndexButton : Button
 {
  private int indexValue;
  [
   Bindable(true),
   Category("Behavior"),
   DefaultValue(0),
   Description("The index stored in control state.")
  ]

 public int Index
 {
  get
  {
   return indexValue;
  }
  set
  {
   indexValue = value;
  }
 }

 [
  Bindable(true),
  Category("Behavior"),
  DefaultValue(0),
  Description("The index stored in view state.")
 ]

 public int IndexInViewState
 {
  get
  {
   object obj = ViewState["IndexInViewState"];
   return (obj == null) ? 0 : (int)obj;
  }
  set
  {
   ViewState["IndexInViewState"] = value;
  }
 }

 protected override void OnInit(EventArgs e)
 {
  base.OnInit(e);
  Page.RegisterRequiresControlState(this);
 }

 protected override object SaveControlState()
 {
  //調用基類的方法,從基類得到控制項狀態的基值
  //如果indexValue不等於並且基類的控制項狀態不為null
  //使用Pair作為便利的資料結構來高效儲存(和在LoadControlState方法中還原)
  //由兩部分組成的控制項狀態 
  object obj = base.SaveControlState();
  if (indexValue != 0)
  {
   if (obj != null)
   {
    return new Pair(obj, indexValue);
   }
   else
   {
    return (indexValue);
   }
  }
  else
  {
   return obj;
  }
 }

 protected override void LoadControlState(object state)
 {
  if (state != null)
  {
   Pair p = state as Pair;
   if (p != null)
   {
    base.LoadControlState(p.First);
    indexValue = (int)p.Second;
   }
   else
   {
    if (state is int)
    {
     indexValue = (int)state;
    }
    else
    {
     base.LoadControlState(state);
    }
   }
  }
 }
}
}

  代碼討論

  IndexButton 控制項的實現闡釋了三個任務,必須執行這三個任務才能使控制項參與控制項狀態:

  · 重寫 OnInit 方法並調用 RegisterRequiresControlState 方法向頁面註冊,以參與控制項狀態。必須針對每個請求完成此任務。

  · 重寫 SaveControlState 方法,以在控制項狀態中儲存資料。

   · 重寫 LoadControlState 方法,以從控制項狀態載入資料。此方法調用基類方法,並擷取基類對控制項狀態的基值。如果 indexValue 欄位不為零,而且基類的控制項狀態也不為空白,Pair 類便可作為方便的資料結構使用,用來儲存和還原由兩部分組成的控制項狀態。

  分析總結

  從MSDN上的一系列的技術參考來看,ControlState應該是主要在自訂控制項上使 用,“ASP.NET 頁架構提供了 ControlState 屬性作為在伺服器往返過程中儲存自訂控制項資料的方法”,這是MSDN上的原句,ASP.NET2.0隻是為ControlState提供了一個基礎,當 ControlState是一個自訂的狀態保持機制,也就是說保持狀態的機制需要你開發人員自己去完成,而不像ViewState,它有自己預設的狀態 保持機制。在自訂控制項使用ControlState也許才是微軟本意了,為的就避免在頁面層級禁用掉ViewState後,自訂控制項還能正常運行。當 然這裡的意思就是,某些控制項的正確運行是依賴於它的狀態資訊的,在ASP.NET1.1中,如果禁用了ViewState,這樣的控制項就無法正確運行了。 但引入了ControlState後就不同了,因為ControlState是禁用不掉的。
 
  所以微軟才提醒開發人員“請僅對那些在 回傳過程中對控制項至關重要的少量關鍵資料使用控制項狀態,而不要將控制項狀態作為檢視狀態的備用選項使用”。明確說出,ControlState和 ViewState完全是兩個東西,雖然它們可以完成相同的任務,新推出的ControlState既不是用來替代ViewState也不是用來做 ViewState的替補。它的使命是彌補ViewState的所不能完成的任務,讓開發人員開發出更加健壯的控制項。例如說,開發的自訂控制項某個狀態是 至關重要的,缺少它就自訂控制項不能正常工作,那麼ControlState就該上場了。而且ControlState是自訂的狀態保持機制,也限制了 ControlState自由的使用,你不但要在OnInit 方法並調用 RegisterRequiresControlState 方法向頁面註冊,而且要重寫SaveAdapterControlState(),LoadAdapterControlState(object state)兩個方法自己去實現要儲存什麼,怎樣儲存。根據我現在的理解,如果你需要儲存該控制項的10種不同狀態,那你就得一一儲存,再一一載入上去。從 這點也就看出了微軟的初衷了,那不是很明顯嗎,如果不需要ControlState那就不使用它吧,否則怎麼它什麼都讓我們開發人員去做呢?

   這隻是基礎了,剛才我說了,似乎微軟也是這麼說的,ControlState針對的是自訂控制項,其實我們真的要去開啟基本控制項例如Label控制項的 ControlState,微軟也是允許的,這就是稍深的內容了,這就涉及到控制項適配器了(ControlAdapter)。如果需要瞭解這方面的內容, 請看用控制項適配器開啟基本控制項的ControlState。http://sifang2004.cnblogs.com/archive/2006 /06/01/415288.html

  附錄

  為了更加充分理解上面的內容,需要對以下內容有個瞭解:

  Pair 類

   用作儲存兩個相關對象的基本結構。它是在整個 ASP.NET 中(在如頁面狀態管理工作期間或配置節處理常式的過程中)有多種用法的工具 + 生產力類。可以在自己的代碼中需要包含兩個相關對象的結構的任意位置和不一定需要 資料繫結的位置使用 Pair 類。Pair 類不將其對象引用 First 和 Second 封裝在屬性中;該類直接將它們作為公用類欄位公開到所有調用代碼。 

  Pair 類在頁狀態保留實現中有多種用法。最常見的用法是同時作為 ViewState 和 ControlState 集合的容器。在這種情況下,First 屬性用於 ViewState,而 Second 用於 ControlState。

  PageStatePersister 類

   HTTP 要求和響應原本是無狀態的。要在 HTTP 要求之間保持狀態資訊,ASP.NET 伺服器頁可以儲存 Page 狀態。此狀態稱為檢視狀態,它包含頁和控制項設定及資料,這些設定和資料使得頁和控制項看起來就像在上一次將它們提交到伺服器然後又返回到用戶端時,使用者所看 到並與之互動的頁和控制項一樣。有幾種機制可在對相同頁的連續請求之間儲存檢視狀態。PageStatePersister 抽象類別表示這些狀態資訊儲存機制的基類。

  要在不能支援現有檢視狀態持久性機制的用戶端上保留檢視狀態,可以擴充 PageStatePersister 類,引入您自己的檢視狀態持久性方法,並且可以使用頁適配器將 ASP.NET 應用程式配置為根據為其提供頁的用戶端的類型使用不同的檢視狀態持久性機制。從 PageStatePersister 類派生的類必須重寫 Save 抽象方法,以便在持久性介質中儲存檢視狀態和控制項狀態,同時重寫 Load 方法以提取狀態資訊。如果想知道如何寫PageStatePersister的衍生類別,請參考檢視狀態持久性機制。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.