開發WinFrom的程序員可能不會在意維護應用程序的狀態,因為WinFrom本身就在客戶端運行,可以直接在內存中維護其應用程序狀態。但ASP.NET應用程序在服務器端運行,客戶端使用無狀態的http協議對ASP.NET應用程序發出請求,ASP.NET應用程序響應用戶請求,向客戶端發送請求的HTML代碼,服務器并不會維護任何客戶端狀態??紤]一個有成千上萬并發用戶的服務器,如果為每一個用戶都維護狀態的話會耗費非常多的資源。
由于使用無狀態的http協議作為web應用程序的通信協議,當客戶端每次請求頁面時,ASP.NET服務器都會重新生成一個網頁的新實例。這意味著客戶端用戶在瀏覽器中的一些狀態或者是一些修改都將丟失。
記得在使用ASP的時候,為了保存每個文本框的值,在數據提交前使用了大量的session變量來保存每個文本框的值,并在頁面重新生成后將這些會話變量中的值一一賦給每個文本框,這是一種相當費時費力的工作。
而ASP.NET提供了狀態管理的技術視圖狀態技術會自動保存及分配每一個控件的狀態,此外提供了一種控件狀態技術。
視圖狀態(ViewState):使用一個或多個隱藏域來保存控件的數據。
當然我們也可以使用其保存自己的狀態數據,方法是使用ViewState這個內置對象,ViewState[key]=value;。這個對象是字典類型。當要取其值的時候需要進行類型轉換,int i=(int)ViewState[key];因為值在ViewState里的存儲類型是Object。存儲在ViewState里的數據可以是簡單的數據類型也可以是自定義的類型,但自定義的類型必須支持序列化(也就是在聲明類的時候要在類上面寫上[Serializable]級別)。不過要弄清楚的是用ViewState保存數據僅限于當前用戶當前頁面,并不能跨頁面傳遞信息。由于其默認可以保存大部分控件的狀態,所以其在服務器端與客戶端來回傳遞時將占用大量的網絡帶寬,并且由于其是存儲在客戶端的,所以會占用過多的客戶端的內存從而影響執行效率。所以對于有些不需要保存狀態在ViewState里的控件我們可以通過其EnableViewState屬性來禁用其視圖狀態。也可以通過<%@ Page EnableViewState="false">來禁用該頁面的所有視圖狀態。視圖狀態是通過ASP.NET引擎將其保存在一個隱藏域HiddenField里,<input type="hidden" name="_VIEWSTATE"id="_VIEWSTATE" value="這些狀態以鍵/值對集合的形式保存并且以Base64編碼格式編碼">。由于Base64編碼的字符串可以由很多工具解碼(如ViewStateDecoder),所以對于敏感的數據保存在視圖狀態里將很危險。如果非要將敏感信息存放在視圖狀態里,可以在<%@ Page
ViewStateEncryptionMode="Always">或在Webconfig的pages節點里設置ViewStateEncryptionMode的值。也可以在后置代碼里Page.RegisterRequiresViewStateEncryption();但前提是在@Page和pages節點里ViewStateEncryptionMode沒有設置為Never。這時會多一個隱藏域名字為__VIEWSTATEENCRYPTED。
控件狀態(ControlState):當開發自定義控件時,保存控件的狀態數據。
為了讓控件正常工作,有時需要存儲控件狀態數據。例如,如果編寫了一個自定義控件,其中具有顯示不同信息的不同選項卡,為使該控件如預期一樣工作,控件需要知道在往返過程中選擇的是哪個選項卡。ViewState 屬性可用于此目的,但開發人員可能在頁級別關閉了視圖狀態,從而有效地中斷控件。為解決此問題,ASP.NET 頁框架在 ASP.NET 2.0 版中公開了一種稱為控件狀態的新功能。ControlState 屬性允許保持特定于控件的屬性信息,不像 ViewState 屬性一樣可以關閉。若要使用控件狀態,控件必須在初始化過程中調用 RegisterRequiresControlState 方法,然后重寫 SaveControlState 和 LoadControlState 方法。
默認情況下,ASP.NET 頁框架將控件狀態存儲在頁的一個隱藏元素中,視圖狀態也同樣存儲在此隱藏元素中。即使禁用視圖狀態,或是使用 Session 管理狀態時,頁面中的控件狀態仍會傳輸至客戶端,然后返回到服務器。在回發時,ASP.NET 會對隱藏元素的內容進行反序列化,并將控件狀態加載到每個注冊過控件狀態的控件中。
從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那就不使用它吧,否則怎么它什么都讓我們開發人員去做呢?
有關鏈接:http://kendezhu.VEvb.com/blog/810562的3和5
http://www.49028c.com/think-jerry/archive/2007/05/24/758240.html及其下一篇
補:cookiessession application
Session
Session與ViewState類似,也可以保存任何標準數據類型和任何派生自object的類型的對象,使用方法也一樣。但Session可以跨頁面保存,同一個用戶在不換瀏覽器的情況下跳轉到其他頁后仍然能通過Session得到前一個頁面保存的數據。Session狀態與ViewState不同,它是保存在服務器端的。ASP.NET會給每一個Session創建一個唯一的SessionID(120位標識符),這個SessionID將會以Cookie或Url的方式發送到客戶端,這樣服務器端就能根據客戶端的SessionID來維護每個客戶端的會話了(所以不管程序中是否使用Session["鍵"]=值在服務器端建立了會話,都會有SessionID發到客戶端,只不過建立了會話,SessionID就有用武之地了,就可以用來維護每個客戶端的會話了)。但當客戶端用戶關閉了瀏覽器,使用不同的瀏覽器,長時間沒操作導致會話超時都會導致服務端會話狀態丟失。會話狀態默認是存儲在服務器的內存里,這樣做固然有效率上的優勢,但會占用大量的服務器端內存,我們可以將其保存到數據庫等其他地方,下面就來學習一下在webconfig中配置會話狀態:
在webconfig的system.web節點下添加sessionState節點如下配置:
<system.web>
<sessionState
cookieless="UseCookies" cookieName="ASP.NET_sessionid"
mode="SQLServer" timeout="20"
sqlConnectionString="Data Source=./sqlexPRess;Integrated Security=SSPI"
sqlCommandTimeout="30">
</sessionState>
</system.web>
cookieless設置SessionID是用Cookie還是用Url發送到客戶端,或是通過檢測決定。cookieName設置保存SessionID的Cookie的名字。mode設置Session狀態的保存方式,默認是InProc保存在服務器內存里,這里設置了保存在SQLServer數據庫里。sqlConnectionString設置連接字符串。sqlCommandTimeout設置超時值。
設置完之后,在Visual Studio 2008命令提示符下輸入:
aspnet_regsql.exe -S ./SQLEXPRESS -E -ssadd -S后面跟的是數據庫服務器名稱
添加后服務器里會多了一個數據庫ASPState,要想移除該數據庫,在提示符下輸入:
aspnet_regsql.exe -S ./SQLEXPRESS -E -ssremove
但這時狀態表位于tempdb數據庫里,所以重啟SQLServer的話會導致會話信息丟失,要輸入:
aspnet_regsql.exe -S ./SQLEXPRESS -E -ssadd -sstype p
這樣狀態表就會出現在ASPState數據庫里了,并且會話信息會持久保留。
如果要將狀態數據保存在自己的數據庫里,要輸入:
aspnet_regsql.exe -S ./SQLEXPRESS -E -ssadd -sstype c -d 數據庫名
然后在sessionState節點里修改屬性:
allowCustomSqlDatabase="true" 允許使用自定義數據庫
sqlConnectionString="Data Source=./sqlexpress;Initial Catalog=tempdb;Integrated Security=SSPI"鏈接字符串加數據庫
相關鏈接:
http://www.49028c.com/shoru/archive/2010/02/19/1669395.html
http://www.49028c.com/flier/archive/2004/08/04/30226.html(一)
http://www.49028c.com/flier/archive/2004/08/07/30902.html(二)
Application
Application的用法與Session一樣,并且也是保存在服務器端。但Application是一個全局對象,不僅局限于一個頁面一個瀏覽器,它被所有用戶所共有。而且其沒有超時的概念,除非服務器關閉或重啟。最常用的例子是網頁計數器:
protected void Page_Load(object sender, EventArgs e) { int i=0; if (Application["PageCount"]!=null) { Application.Lock(); 加鎖,防止多用戶同時訪問(并發訪問) i = (int)Application["PageCount"]; i++; Application["PageCount"] = i; Application.UnLock(); 操作完后解鎖 } else { Application["PageCount"] = 0; } Label1.Text = i.ToString(); }
新聞熱點
疑難解答