[ASP.NET的二三事] Lesson 5 ASP.NET的狀態管理 Vol. 2 (State Management–Client-Side Statemanagement)

[ASP.NET的二三事] Lesson 5 ASP.NET的狀態管理 Vol. 2 (State Management–Client-Side Statemanagement)

本Lesson 將分享第一條主線:Client-Side StateManagement,其中包含了下列方法:

1.ViewState

ASP.NET會透過ViewState來保持頁面請求間的控件狀態,而我們也可在其中增加自訂的資訊

 

2.Control State

控件的狀態可以允許我們來保留控件的資訊,而且不一定要透過ViewState

這對自訂控件的開發很有用,假如ViewState被關閉了(控件或是Page物件的EnableViewState)

控件狀態仍然有效。

 

3.Hidden Fields

就像ViewState,HTML的隱藏欄位可以儲存資訊,而且不讓使用者在瀏覽器上看到

但這個欄位的資訊仍可以透過表單傳送來傳回後端,並進行進一步的處理

 

4.Cookie

Cookies儲存的資訊會放在瀏覽器之中,而且在每次頁面請求的時候,送回給同一台伺服器

若是在整個網站中要讓多個頁面同時存取並儲存狀態資訊,Cookie是最佳方案之一

 

5.QueryString

QueryString將資料儲存在瀏覽器的URL後面,因此可以被使用者看的一清二楚

另外,當我們想要使用者可以透過URL在Email或者是即時通訊中保留狀態,就使用QueryString

 

 

現在將針對Client-Side的狀態管理進行進一步的探討

1.ViewState

當然,ViewState是ASP.NET用來儲存頁面請求之間特定使用者(User-Specific)資料的預設機制。

ViewState的資訊是儲存在Page.ViewState的屬性中,採鍵值對型態的物件

這個物件在同一頁面的請求間都保留了狀態資訊,這個物件又稱為StateBag

當ASP.NET頁面產生的時候,目前的狀態(或物件)就會被雜湊(Hash)成字串型態

被儲存到HTML的隱藏欄位中(名為__ViewState)

假如資料過長的話,ASP.NET也會自動分隔放入數個隱藏欄位。

為了更優化效能以及安全性,ViewState的資料被ASP.NET所雜湊、壓縮並且被編碼成Unicode

 

 

ViewState的安全機制:

ViewState通常會透過Message Authentication Code來加密(MAC),因此假如敏感資料使用了ViewState來暫存的話

我們可以透過設定Page屬性的ViewStateEncryptionMode來達成(或Web.Config來設定整個網站)

不過這樣也會造成加解密的效能耗費,因此我們可以考量設計加解密的範圍。

然而雖然加密足以應付大部分的情境,不過敏感性的資料,我們仍然盡量不要送到客戶端去!

 

若我們要關閉ViewState(預設Page與所有控件都開啟ViewState),像是Label我們就不需要ViewState

過多的ViewState就造成網站效能的問題,因為頁面總是會將ViewState的資訊在客戶與伺服器之間傳來傳去,

所以若要最小化ViewState的話,透過設定控件的EnableViewState屬性就可以設定所有控件是否要使用ViewState

PS.其實早期的ASP.NET 2.0以前,資料與外觀的狀態是存在一起的,因此假如關閉了控件的ViewState

將會失去了外觀的設定資料,不過在2.0以後,控件的資料與外觀的ViewState被分開儲存,因此關閉了EnableViewState。

外觀的狀態仍然可以正常運作,這有助於降低頁面ViewState的大小。

 

只是我們要自行的新增資料到ViewState的話,僅適合在我們需要將資料在單一網頁內做傳遞

因此ViewState不可用在跨網頁的傳值上,就如Post一樣,將資料送回給伺服器

ViewState適合傳送各種物件型態的資料,不會像Cookies一樣被限制為字串的格式,只需要能被序列化(Serializable)的資料就可以了。

 

 

2.Control State

回想之前,我們可以自行關閉控件的ViewState機制,假如我們有撰寫自己的自訂控件的話

我們可能會需要類似於ViewState的機制滿來儲存控件的狀態(而且這狀態不能被關閉,不然控件就會失效了)。

因此我們必須在自訂控件的時候,可以進行一些小動作

包含覆寫了OnInit,並呼叫Page.RegisterRequiresControlState的方法,並將控件實體當參數傳入,然後若有自行的狀態控管機制

我們可以再覆寫SaveControlState以及LoadControlState的方法,來實作自己特定的狀態存取機制。

 

 

3.Hidden Fields

隱藏欄位其實就像ViewState儲存訊息的機制一樣不會被顯示,不過假如開啟原始碼的話,仍然會被看的一清二楚

隱藏欄位的特性跟ViewState一致,也就是僅適合單一頁面的狀態保存。但是他不具備雜湊、壓縮、加解密的機制

而且假如使用了隱藏欄位要使用送出(Submit)的機制來傳遞頁面到伺服器端的話,必須採用表單POST機制

而不能僅僅採用Link的方式(HTTP GET)就取得隱藏欄位的資料。

4.Cookies

Web應用程式在頁面的請求之間基本上都需要能區別使用者的資料

也就是說必須在多個請求間確認是否為同一個使用者,這樣的追縱機制就可以被Cookie來完成。

Cookie是一個儲存在客戶端字串資料型態的機制(存在HttpCookie)

我們可以也可以去修改他們(在瀏覽器的記憶體中)

這是最普遍被用在識別單一使用者在單一網站的機制,Web應用程式其實是透過回應時,綁在HTTP Header中回傳給客戶端

若客戶端的請求沒有包含Cookie的話,在初次請求的回應中會連同Cookie一同傳回

未來瀏覽器針對相同站台的網頁都會附帶Cookie一起傳給伺服器

因此Cookie也不能將狀態傳送到另一個站台(預設是同一個HostName)

但是我們也可以進行進一步的控制,只要設定Path屬性或是Domain

就可以設定Cookie僅在特定Web站台的特定目錄結構或是網站領域下有效。

ASP.NET提供了完整的API來存取Cookie,此外,Cookie提供了彈性的過期屬性

(為什麼說彈性,因為可以短至幾分鐘,長則數月)

不過假如沒有設定Expire的屬性的話,則預設是客戶端關閉瀏覽器就會過期了。

image

 

關於Cookie的限制

每個Cookie大小都是關系到瀏覽器。每個Cookie最大長度是4KB,基本上每個站台最多20個Cookie

不過假如真的要操作許多資料的話,我們可以透過陣列的方式,將多筆資料來指定同一個名稱的Cookie來儲存

例:

Response.Cookies("Info")("VisitTime") = DateTime.Now.ToString();
Response.Cookies("Info")("Name") = "Huang IP";

 

5.QueryString

這個機制是被用在請求單一網頁的時候,將具識別性資料透過變數格式儲存的一個常見方法。

為什麼說識別性資料:主要是透過使用者發出的請求資訊,而非完整內文

包含查詢字串、頁碼、國籍、查詢的編號等資訊。通常需要進一步的查詢明細…

QueryString會將資料合併在URL的後面,透過?的符號連接許多的參數與值,參數值則透=符號連接

若有多個參數,則再透過&符號隔開

例:

http://www.pin0513.com?birthday=0513(假的)

http://www.pin0513.com?birthday=0513&sex=male&location=taiwan(假的)

透過這樣機制,將狀態透過資訊保存於URL,傳遞到伺服器(如Lesson2所言,綁在HTTP的Response中)

而ASP.NET可以透過Request.QueryString["birthday"]來取得0513的值。不過ASP.NET沒有工具可以組QueryString

只能透過自己用程式來組合URL,不過正因為是透過URL來保存資料

所以這著實也提供了一個簡單的方式來讓頁面資訊可以傳遞(不像是ViewState、HiddenField無法跨頁面傳遞)

然而客戶端的瀏覽器對於URl有些僅能支援2083個字元長度,此外因為是透過URL,所以資訊會顯露在URL的地址欄中

 

QueryString有一個很特別的好處是,這是唯一可以將狀態資料保存並透過URL讓電子郵件傳遞或是書籤記錄下來的機制。

因此像是帳號認證的開通信件,通常也都會用到這個方案(PS.Email用途的URL長度限制為70字元,而即時通訊則限制為400字元,查證中)

 

QueryString的安全性

我們對於QueryString來的資料必須要檢驗(其實不只,只要是來自於使用者的資料都要假設是惡意)

例如,我們可以將QueryString中綁定查詢每頁筆數的資料,假如一般是10筆。若不檢查QueryString

使用者一旦可以任意地設定為10000筆的話,這時就會造成許多問題,例如 DoS的風險

其他像Cookie或是QueryString的資料理應要經由HTML Encode,因為Browser不會對HTML的Tag以及Script進行處理。

(或是透過在取得QueryString的時候,偵測HttpRequestValidationException來檢驗QueryString)

 

 

本回分享了如何在Client-Side進行狀態管理的機制與原理

但沒有絕對沒問題的情境

有的時候可能要搭配混著使用

依照自己與客戶的需求來決定最適合的方案。

下次將分享Server-Side 的狀態管理。

 

 

參考資料:

書籍的資料來源:MCTS for ASP.NET