【C#.NET】ASP.NET狀態管理之五:隱藏欄位、ViewState、ControlState

來源:互聯網
上載者:User
一、使用隱藏欄位

Session、Application和Cache都是儲存在伺服器記憶體中的。一般來說我們是無權訪問用戶端的機器,把資料直接儲存在用戶端的(Cookie是一個例外,不過Cookie只能儲存不超過4K的字串)。我們可以想一下還有哪裡可以讓我們暫時儲存資料的?那就是頁面!如果我們在Web頁面中放置一個Label控制項,然後設定它隱藏。那麼我們就可以使用這個Label來儲存一些臨時資料,供當前頁面的程式使用。

在ASP.NET中,我們還可以使用隱藏欄位來進行類似的工作,和Label不同的是,在隱藏欄位中填寫的內容不會直接顯示在IDE的設計檢視中。由於我們儲存的這些資料根本不需要顯示給使用者看,所以用隱藏欄位更合理一些。

<asp:HiddenField ID="HiddenField1" runat="server" Value="編程快樂" />

在代碼中可以直接存取隱藏欄位的Value屬性獲得其值。

Response.Write(HiddenField1.Value);

不過,這樣做還有幾個不合理的地方。

·      資料直接暴露給使用者。

·      只能儲存字串資料。

二、使用 ViewState

ASP.NET引入了ViewState(檢視狀態)的概念。從這個名字上我們大概可以體會出,ViewState主要是用來存放和視圖有關的一些狀態。比如,在使用者註冊時使用者填寫了一大堆資料,提交頁面後系統返回了一個“使用者名稱重複”的出錯資訊,此時先前使用者在頁面上填寫的一些註冊資料全部沒有了。使用者會是什麼感覺呢?我想大多數使用者會很惱火。ASP.NET通過ViewState自動儲存控制項的狀態。你可能也發現了,文字框中的資料在頁面提交後還是存在的。

同時,我們也可以利用ViewState來儲存一些程式需要的資料。ViewState中的資料預設是使用base64進行編碼的,因此,使用者不能直接看到裡面的資料。我們在代碼中可以這樣添加一個ViewState項:

ViewState["test"] = "編程快樂";

開啟頁面,觀察原始碼,ViewState就在這裡:

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="XT+Q3cCGrb+qjUKNB1N7x

CMUgAMjbpmAwtMtwPE+b5Ii8uRFaO42AgKyR+u9T0Be" />

既然ViewState是存在頁面上的,那麼ViewState肯定是不能跨頁面使用的,而且每個使用者訪問到的ViewState都是獨立的。此外,ViewState也沒有什麼聲明周期的概念,頁面在ViewState就在,頁面關閉了ViewState就關閉了。

觀察上面的ViewState,是不是找不到“編程快樂”這幾個字的影子呢?請在頁面上隨便加入一個按鈕,按鈕的Click事件處理方法如下:

Response.Write(System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(

Request["__VIEWSTATE"])));

5-1所示,單擊按鈕後頁面顯示如下。

圖5-1  對ViewState資料進行base64解碼

我們對ViewState資料進行base64解碼後就能看到“編程快樂”的字樣了。不過,現在的那串字串還是很亂。其實,ASP.NET首先對ViewState中的資料進行序列化,然後再使用base64編碼後儲存在頁面的隱藏欄位中。base64不是什麼密碼編譯演算法,只是一種編碼演算法,任何人都能對base64進行反     編碼。

三、 ViewState的安全與效能

如果我們需要在ViewState中儲存一些相對比較機密的資料(當然,非常機密的資料不建議你儲存在ViewState中),又如何保證ViewState的安全性呢?一般來說可以從兩個方面入手。

1.保證用戶端提交過來的ViewState沒有被修改。我們做Web應用程式,心中要有這樣一個意識,那就是用戶端的一切都是不可相信的。大家可能以為只有我們提供了諸如TextBox等控制項,使用者才能修改。其實這種觀點是錯誤的,雖然DropDownList中的內容只允許選擇不允許修改,但完全可以偽造一個頁面進行提交。對於ViewState也是同樣道理,為了進一步的安全,我們需要驗證用戶端發回的ViewState是否已經被修改了。

2.保證使用者不能直接看到ViewState中的資料。說白了就是對ViewState進行加密。

在ASP.NET 2.0中,我們只需要進行簡單地配置就能對ViewState進行驗證和加密,在頁面頭部添加EnableViewStateMac(驗證)和ViewStateEncryptionMode(加密)屬性:

<%@ Page Language="C#"   … EnableViewStateMac="true" ViewStateEncryptionMode="Always" %>

當然,如果你希望為所有頁面的ViewState應用驗證和加密,可以在Web.config的system.Web節點中添加:

<pages enableViewStateMac="true" viewStateEncryptionMode="Always"></pages>

既然ViewState中的資料是序列化後加入的,那麼我們就可以把一些複雜的類型也存放到ViewState中。在介紹Session的時候我們曾建立過一個MyUser自訂類,並把它的執行個體存放到了Session中,後來為了讓StateServer和SqlServer模式的Session也能儲存MyUser類型,我們又為MyUser標記了[Serializable]。在ViewState中儲存自訂類型同樣需要為類型標記[Serializable],那麼在這裡我們使用ViewState儲存MyUser執行個體的代碼就和使用Session差不多。

MyUser user = new MyUser();

user.sUserName = "小朱";

user.iAage = 24;

ViewState["CustomClass"] = user;

讀取代碼:

MyUser user = ViewState["CustomClass"] as MyUser;

Response.Write(user.ToString());

那麼,ViewState中能儲存多少資料呢?暫且不說表單Post的資料是有大小上限的,ViewState是經過序列化和編碼後儲存在頁面中的。如果我們在ViewState中儲存一個擁有100條記錄的DataSet,恐怕頁面就很難開啟了。不信,你可以自己做一個實驗。

DataSet ds = new DataSet();

using (SqlConnection conn = new SqlConnection(@"server=(local)"SQLEXPRESS;database=

Forum;Trusted_Connection=True"))

{

    SqlDataAdapter da = new SqlDataAdapter("select top 100 * from CacheTest", conn);

    da.Fill(ds);

}

ViewState["Data"] = ds;

僅僅只有100條記錄,在ViewState就成這樣了,5-2所示。

圖5-2  濫用ViewState的結果

而且這些資料還要在瀏覽器和伺服器之間往返,佔用的網路流量很客觀。因此,筆者建議你在ViewState中儲存盡量少的資料。如果實在需要在ViewStatge中放置大量資料建議使用maxPageState- FieldLength對ViewState啟用分塊傳輸。

<%@ Page Language="C#"   … maxPageStateFieldLength="100"%>

5-3所示就設定了單個ViewState,不超過100位元組,ViewState分成了幾個部分。

圖5-3  使用maxPageStateFieldLength控制每個ViewState不超過100位元組

我們知道,ViewState不僅僅是我們在使用,ASP.NET會把控制項互動相關的一些資料都存放到ViewState中,但是對於一些不實現任何互動的控制項(比如顯示10條記錄的GridView),你可以設定控制項的EnableViewState屬性為false來讓控制項不使用ViewState,從而減少頁面體積。

四、   ControlState概述

最後,我們再簡單提一下,ASP.NET 2.0提供了ControlState。它用於儲存(自訂)控制項的關鍵資訊。就算頁面或者控制項的ViewState被關閉它還能起作用,彌補了ViewState能被禁止的不足。不過使用ControlState稍顯複雜,我們需要自己序列化複雜物件進行儲存。下面的代碼示範了如何在ControlState中儲存和讀取簡單字串:

PageStatePersister.ControlState = "編程快樂";

Response.Write(PageStatePersister.ControlState.ToString());

五、總結

其實隱藏欄位、ViewState和ControlState的原理差不多,我們來總結一下。

·      儲存的物理位置。表單隱藏欄位。

·      儲存的類型限制。可序列化類別型(直接在隱藏欄位中儲存內容需要自己序列化)。

·      狀態使用的範圍。當前頁面(當前控制項),對使用者獨立。

·      儲存的大小限制。儲存過大資料會導致頁面不能正常開啟,不能正常提交。

·      生命週期。頁面在就在,頁面不在也就不在了。三者始終是依附在頁面的隱藏欄位中的。

·      安全與效能。在用戶端儲存,安全性低。不過,ViewState提供了驗證和加密。

·      優缺點與注意事項。儲存少量資料非常方便簡單。但需要注意不要儲存敏感性資料,不要儲存過大的資料。它們和前面說的Cookie、Session與Application不同。雖然Cookie也是儲存在用戶端,每次提交都附加在HTTP頭中進行提交,但是它的資料量畢竟不大,起了一個標記的作用。Session和Application都是儲存在伺服器端的,不會參與頁面往返過程。隱藏欄位、ViewState和ControlState始終參與往返,而且序列化和還原序列化會消耗一定資源,因此,儲存過大的資料會導致網頁載入過慢,浪費伺服器頻寬。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.