介紹
本文主要講解Asp.Net應用程序中的狀態管理技術(Asp.Net中有多種狀態管理技術),并批判性地分析所有狀態管理技術的優缺點。
背景
HTTP是無狀態的協議。客戶端發起一個請求,服務器響應完請求后,立即斷開。服務器斷開后,所有因請求而分配的資源會全部被清除。這些資源包括在請求期間創建的對象,分配的內存等等。Windows應用程序開發者可能會感到很驚訝,因為他沒有辦法依靠對象和成員變量來跟蹤Web應用程序的當前狀態。
如果我們要跟蹤用戶在多個頁面訪問間,或同一頁的多個訪問間的信息,我們就需要使用由ASP.NET提供的狀態管理技術。狀態管理是由ASP.NET用以讓開發者在相同或不同頁面的多個請求中保存交互狀態和頁面信息的處理過程。
狀態管理分類
ASP.NET主要提供了兩種類型的狀態管理技術:
● 客戶端狀態管理
● 服務器端狀態管理
當我們使用客戶端狀態管理技術,與狀態有關的信息將被存儲在客戶端。此信息將每次請求和響應中的來回傳輸。這可以看成是:
注:圖片來自微軟出版社的書。
這種狀態管理主要的好處是,我們減少了服務器保存狀態信息的壓力,它節約了大量服務器內存。客戶端狀態管理的負面影響是,它需要更多的帶寬,因為相當數量的數據需要來回傳輸。但是還有一個比帶寬占用更大的問題。客戶端狀態管理讓信息的來回傳輸,因此用戶信息可能在傳輸過程中被人中途劫持。所以我們不能將敏感信息,像密碼、信用卡號和應付金額存在客戶端,這些東西需要用服務器端狀態管理技術來保存。
跟客戶端狀態管理技術相比,服務器端狀態管理技術將所有的狀態信息保存在內存中。它的缺點是占用更多內存。優點是用戶的機密和敏感信息更安全。
注:圖片來自微軟出版社的書。
我們不能絕對地說用哪一種狀態管理技術好。根據信息的類型和大小,我們必須將客戶端和服務端狀態管理技術結合。現在讓我們看看,在客戶端和服務端上我們可以用多少不同的方式來管理狀態。
客戶端狀態管理技術
● View State
● Control State
● Hidden fields
● Cookies
● Query String
服務端狀態管理技術
● Application State
● Session State
View State
在同一個頁面的請求中,ASP.NET使用這個機制來跟蹤控件的值。我們也可以向View State中添加自定義的值。ASP.NET 自動將控件的信息保存在View State中,然后在回發過程中的頁面渲染前將它從View State中取回。
如果我們需要使用viewsstate
存儲自定義的信息,我們只需要記住 viewstate
是 一個dictionary
類型。我們可以把自己的數據作為鍵值對保存在viewstate中
(如以下代碼所示). 在request過程中,這個控件的值也會被哈希化到這個字典對象中,然后在response過程中被填充回去。
由于這些信息保存在頁面本身中,ASP.NET會信息進行加密。
我們可以在 web.config 調整相關的加密參數。
<Configuration> <system.web> <pages viewStateEncryptionMode="Always"/> </system.web> </configuration>
或者在頁面聲明中:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" ViewStateEncryptionMode="Always"%>
讓我們看一下一段應用viewstate的代碼。 我們寫一個帶textbox 和button的小頁面。我們主要是想在text box中寫入一些信息,然后看看ASP.NET是怎樣將信息保存在view state中的。我們也會將自定義的信息存儲在view state中。當我們運行頁面,然后將我的名字寫入textbox,并按下button后,觸發一個回發,但是我的名字還留在 textbox中
。 Viewstate
讓頁面回發之后狀態的保持成為可能。這個頁面如下所示:
讓我們看一下頁面源代碼,view state看起來就像:
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTkwNjc4NTIwMWRkfIZa4Yq8wUbdaypyAjKouH5Vn1Y=" />
現在讓我們嘗試著將自己信息添加進viewstate 。我們將跟蹤用戶收到的回發。當用戶點擊button的時候,我們就將保存在回發內容中的值加1.實現的代碼如下所示:
protected void Page_Load(object sender, EventArgs e) { if(IsPostBack == true) { if (ViewState["number"] != null) //我們取出,增加,然后再次存儲 { ViewState["number"] = Convert.ToInt32(ViewState["number"]) + 1; } else //第一次postback,我們寫入信息 { ViewState["number"] = 1; } Label1.Text = ViewState["number"].ToString(); } }
當我們運行這個界面然后點擊按鈕去完成一次回發后,這個頁面將會展示之前我們回發完成后存儲在viewstate中的信息。
View State默認被開啟,我們可以將每個控件的EnableViewState屬性設為false來禁止view State。這會減少服務器處理時間和減小頁面大小。
Control State
現在我們都知道什么是viewstate 并且我們也知道我們可以在頁面上禁止某個控件的viewstate。但有假如我們要開發一個自定義控件,控件內部使用viewstate 來保存信息,但是用戶可能禁止我們控件的viewstate。為了避免這個問題,我們可以使用一個跟viewstate原理相似,但是控件使用者無法禁用它,這種狀態管理技術就叫做ControlState 。Control states內置于自定義控件,它的工作原理跟viewstate 相同。
為了在自定義控件里面使用control state,在初始化的時候,我們必須重寫OnInit方法并且在初始化的時候調用RegisterRequiresControlState方法。然后,我們必須重寫SaveControlState 和
LoadControlState
方法。
Hidden Fields
Hidden field是ASP.NET提供的一個控件,我們可以用它來保存一些信息。Hidden Fields唯一的限制就是:Hidden Field中的值只會在Http的post請求時被一起發往服務端。 比如說,一個button點擊。它在Http的get請求不會生效。讓我們使用HiddenFields做相同的實驗來跟蹤回發的內容。
(注意: hidden field內部也使用ViewState
.)
// 在Hidden Field保存一些信息 ----------------------------------------------------------- int newVal = Convert.ToInt32(HiddenField1.Value) + 1; //Hidden field 默認值為0 HiddenField1.Value = newVal.ToString(); Label2.Text = HiddenField1.Value;
當我們運行頁面,單擊按鈕觸發一次回發后,這個頁面展示了回發后Hiddenfields 中值。(詳見上面代碼)
Cookies
在某些時候下,我們需要在多個頁面的請求間保存一些信息。到目前為止,我們所討論的狀態管理技術都是用在單個頁面的多次請求中的。現在讓我們看看多個頁面請求中的用來保存消息的技術。
Cookies是指少量的可被保存在用戶電腦文本文件中的數據。這些信息可以被服務器讀取,也可以在不同頁面的訪問,或在用戶對同一個頁面的多次訪問中被請求。讓我們使用cookie做同樣的實驗來跟蹤回發的內容。
我們不可能用Cookie跟蹤到回發的內容,因為cookie保存在用戶的電腦中。所以實際上,我們通過觀察用戶觸發回發的次數來判斷。
當我們運行這個頁面,然后觸發一次回發后,這個頁面會顯示出回發結束時保存在Cookies中的值(詳見代碼)。Cookies可以有多個參數來比如像Cookie的有效期,存活周期等。這些參數可以像這樣操作:
Response.Cookies["number"].Expires = DateTime.Now.AddDays(1);
這個Cookies從它創建后存活1天。
Query Strings
Query strings常被用來保存標識特定頁面的變量,比如搜索結果或頁碼。Query strings就是附加在頁面下方page URL中的信息。他們可以被用于保存/傳遞信息從一個頁面到另一個頁面或者同一個頁面。讓我們現在使用Query strings來保存回發的內容。
//GetDataItem from querystring if (Request.QueryString["number"] != null) //Lets retrieve, increase and store again { Label4.Text = Request.QueryString["number"]; } //set in query string int postbacks = 0; if (Request.QueryString["number"] != null) //Lets retrieve, increase and store again { postbacks = Convert.ToInt32(Request.QueryString["number"]) + 1; } else //First postback, lets store the info { postbacks = 1; } Response.Redirect("default.aspx?number=" + postbacks);
這里有一點要注意的是:在同一個頁面中,我們不能將要回發的信息保存在query string中。原因是:每次我們使用query string的時候,它都會創建一個新的Url,它產生一個新的請求。所以,現在實際上,我們通過跟蹤點擊的次數來判斷頁面中狀態值的變化。query string的設計思想是,我們可以將一個頁面(假設為頁面A)上的信息傳遞給另一個頁面(假設為頁面B),頁面A上的這些信息可以被頁面B所用。
注意:我們上面對Cookies和QueryString的使用只是為了演示它們的用法。在真實應用時,他們不應該被用于同一個頁面的請求中用來傳遞信息。Querystrings應該用于多個頁面訪問中信息的保存。Cookies應該用于對特定站點的多次訪問(在同一臺電腦上)中數據的保存。
Application State
在ASP.NET中,我們可以用Application State來保存數據。在Web 應用程序(Web Application)中,它是一個可以被所有頁面都訪問到的全局信息共享機制。Application state保存在應用程序的key/value dictionary對象中。它的信息也可以被網站的所有用戶共享。假如我們需要用戶的特定信息,我們最好使用sessionstate.
ASP.NET提供了三個事件,讓我們用來初始化系統變量( Application variables)(在應用程序關閉的時候,清理資源)和響應應用程序錯誤(Application errors):
l Application_Start: 在應用程序啟動時觸發. 我們可以在這個地方初始化系統變量(Application variables)。
l Application_End: 在應用程序關閉時觸發.我們用它來清理系統資源和寫一些應用程序日志。
l Application_Error: 在不能解決的異常發生時觸發.我們可以用它來記錄錯誤日志
讓我們將頁面回發的信息保存在application state中。
//global.asax void Application_Start(object sender, EventArgs e) { Application["number"] = 0; } //In web pages Application.Lock(); Application["number"] = Convert.ToInt32(Application["number"]) + 1; Application.UnLock(); Label5.Text = Application["number"].ToString();
當我們運行頁面點擊按鈕觸發一次回發時,頁面上會顯示回發完成后保存在ApplicationState中的信息。我們可以利用這個對象來跟蹤網站上的所有用戶的點擊數。(詳見代碼)
Session State
如Application state,在Web應用程序中全局存儲對象(a global storage)中的信息可以被所有的頁面共享,但是當我們需要限制當前用戶的信息只能被自己訪問而他人不能訪問的時候,我們就要用到Session State。Session State保存在每個會話中的key/value dictionary對象。Session State的信息只能被當前的用戶訪問,也就是只能被當前的會話訪問。
//global.asax void Session_Start(object sender, EventArgs e) { // Code that runs when a new session is started Session["number"] = 0; } // Web forms Session["number"] = Convert.ToInt32(Session["number"]) + 1; Label6.Text = Session["number"].ToString();
當我們運行頁面點擊按鈕觸發一次回發時,頁面上會顯示回發完成后保存在SessionState中的信息。我們可以利用這個對象來跟蹤當前用戶的點擊數,也就是擁有整個網站當前會話的用戶的點擊數。
客戶端管理技術的優點
· 更好的可拓展性(Better scalability)
· 支持多瀏覽器(Support for multiple browser)
服務端管理技術的優點
· 更好的安全性
· 減少網絡流量
興趣點(Points of Interest)
我寫了這篇小短文主要是因為我的學生有的需要一些關于狀態管理技術的復習材料。我想如果我把它放在CodeProject 上,可能對一些初學者會有幫助。現在,我將總結一下狀態管理技術:
-
當可擴展性要求比較高的時候,我們應該使用客戶端管理技術。
-
當安全性要求比較高的時候,我們應該使用服務端管理技術。
-
ASP.NET默認的頁面級的狀態管理技術是ViewState。
-
我們可以將自定義的信息保存在ViewState中。
-
自定義控件使用ControlState 來保存信息。
-
Hidden field可以為同一個頁面保存信息。
-
Cookies可以為同一臺電腦上的多次訪問提供相關的信息。
-
Query string可以將信息從一個頁面傳遞到另一個頁面。
-
ApplicationState 可以用于保存應該被所有頁面和所有用戶共享的信息。
-
SessionState 可以用于保存應該被所有頁面共享,但只能被當前用戶/會話訪問到的信息。
參考連接
翻譯自:A Beginner's Tutorial on ASP.NET State Management
文章列表