今天在做程序測試的過程中,發(fā)現(xiàn)程序出現(xiàn)只要一個客戶端訪問程序,其他客戶端訪問都受到影響。
后來一查是在程序中設(shè)了靜態(tài)變量的關(guān)系,由于靜態(tài)變量是全局的所以會出錯。
對此問題進(jìn)行學(xué)習(xí)一下(下列內(nèi)容來自各個網(wǎng)頁精華,由于截取不同網(wǎng)頁,如有侵權(quán),請和我聯(lián)系):
利用asp.net 開發(fā)基于B/S模式的應(yīng)用系統(tǒng),經(jīng)常會遇到同一頁面類的各函數(shù)成員之間、 同一會話各頁面之間、不同機器各用戶頁面之間的傳值問題,即要解決數(shù)據(jù)共享的問題。這可以選擇使用Application、Session、cookie、Static、ViewState 等方法實現(xiàn)。
其中Static變量的使用容易出現(xiàn)問題,使用不好會導(dǎo)致數(shù)據(jù)紊亂,給系統(tǒng)造成故障隱患。
用ViewState 作為頁內(nèi)數(shù)據(jù)傳值也是一種較好的選擇 。在C#中,static變量表示該變量屬于類,而不是類的實例。可以說是該類的所有實例共享一個static變量。
asp.net的頁面就是一個類,我們訪問一個頁面。就會在服務(wù)器上實例化一個該類的實例,來響應(yīng)我們的請求。
“所有實例共享一個static變量” 這就意味著,所有的客戶端訪問到的asp.net頁面中static變量都是同一個變量。
由于我們每次訪問asp.net頁面都是一個全新的對象,而不是我們上一次訪問的對象。所以上次頁面訪問時我們對頁面中變量的改動都沒有保留。
遇到這個問題的時候,很多初學(xué)者的直覺就是將這個變量申明為static,自己在測試的時候發(fā)現(xiàn)還真的保留住了頁面的狀態(tài)。竊喜之余沒有發(fā)現(xiàn)這又有引入了另外一個錯誤。因為你要的只是頁面能保留住狀態(tài),而這個狀態(tài)是針對一個客戶端的(session的效果)。而得到的結(jié)果是只要一個客戶端改變了該值所有的其他客戶端都受到了影響(如同Applicatin的效果)。
究其原因這還要從Asp.net的運行機制談起。在C/S模式軟件開發(fā)過程中,我們通常不會關(guān)心應(yīng)用程序是在哪里運行的,變量存放在哪里,客戶端程序就運行在客戶端,服務(wù)器端程序就運行在服務(wù)器端,一般情況下,二者除了數(shù)據(jù)庫中的數(shù)據(jù)外基本沒有其他共享的問題。 所以這時客戶端的用戶大可放心的使用static變量,因為它們就存放在客戶端程序中。
于是我們就習(xí)慣的在做B/S模式的頁面時也用static變量,殊不知Asp.net中的static已 不同于C/S中的static。是因為在Asp.net中所有的用戶將使用同一個static變量。這就意味 著每一個使用該頁面的用戶對該變量的操作將會影響到其他用戶。
解決的辦法之一是可以選擇Asp.net提供的ViewState對象。ViewState對象可以用來保存頁面中的各種變量,甚至是對象。“有些數(shù)據(jù)可以直接保存到ViewState中,諸如字符串 、整數(shù)、布爾、數(shù)組里表、哈希表等。”
“所謂ViewState,實際上是一些鍵值對,ASP.NET通過它維護網(wǎng)頁和服務(wù)器的狀態(tài),并將ViewState封裝成一個或幾個隱藏的表單域傳遞到客戶端。而客戶端提交時,ViewState也 將被提交到服務(wù)器端。這樣后續(xù)的請求可以獲得上一次請求的狀態(tài)。”
只要用變量名稱做索引,如ViewState[“Var ”], 就可以存取變量Var的值,而不管Var是普通變量,還是對象,甚至是內(nèi)存中的一張DataTabl e。服務(wù)器端會為每個連接到該頁面的用戶分別建立一個ViewState,所以ViewState相當(dāng)于 頁面級的Session。相當(dāng)于頁面全局變量,但是一旦退出當(dāng)前頁面,它就會丟失。
ViewState的用法很簡單,如下所示:
1、保存變量到ViewState中(賦值):
ViewState[“times”]=times; //存放普通變量times
ViewState[“Orders”]=dtOrders; //存放DataTable型對象dtOrders
ViewState ["aa"] ="123";
2、讀出ViewState中的值(取值):
times = (int)ViewState[“times”];
dtOrders = (DataTable)ViewState[“Orders”]; string bb = ViewState["aa"].ToString();
讀出變量的值時要進(jìn)行強制類型轉(zhuǎn)換,這是因為當(dāng)變量(不管是int型的普通變量times ,還是DataTable型的對象dtOrders)被存放到ViewState中后統(tǒng)統(tǒng)按Object類型存放。所以 當(dāng)我們從ViewState取出時,一定要轉(zhuǎn)換成相應(yīng)的類型,否則就會報錯。在變量保存到ViewS tate中時,系統(tǒng)會自動轉(zhuǎn)換。
這不是說static型變量就沒用了,在C#中用static聲明的類不用實例化直接使用。正是由于所有用戶共享服務(wù)器端的同一個static變量,所以可以用static型對象來存取一些公用的處理模塊,比如類型轉(zhuǎn)換、變量驗證等工作。所以要根據(jù)具體情況而定。
還有一點需要注意:如果在頁面中多個過程要共享一個對象或變量,我們在頁面類的開始部分定義一個頁面級的全局變量是不行的,static本來可以,但上面說了這種類型的變量不安全,所以這時就可以用ViewState。
ViewState是將數(shù)據(jù)存入到頁面隱藏控件里,不再占用服務(wù)器資源,因此, 我們可以將一 些需要服務(wù)器"記住"的變量和對象保存到viewstate里面。viewstate并不能存儲所有的.net 類型數(shù)據(jù),它僅僅支持String、Integer、Boolean、Array、ArrayList、Hashtable 以及自定義的一些類型。
ViewState 常用于保存單個用戶的狀態(tài)信息,生存期等于頁面的生存期。viewstate是 在本頁面之內(nèi)各函數(shù)間進(jìn)行傳值的 , 至于為什么要使用這種方法是因為在一個事件發(fā)生之后 , 頁面可能會刷新 , 如果定義全局變量會被清零 , 所以要使用 viewstate保持?jǐn)?shù)據(jù),任何事物都有兩面性, 因為ViewState變量在客戶端實際上是用<input type=“hidden ” value=“ADFAIB3P234P-AFAFAF……”/>保存的一個對象,這樣如果要保存的是個對象, 甚 至是個很復(fù)雜的對象(如DataTable),這樣以來就會增加網(wǎng)絡(luò)傳輸?shù)呢?fù)擔(dān)。 使用viewstat e會增加頁面html的輸出量,占用更多的帶寬,這一點是需要慎重考慮的。另外, 由于所有的v iewstate都是存儲在一個隱藏域里面,用戶可以很容易的通過查看源碼來看到這個經(jīng)過base6 4編碼的值,然后再經(jīng)過轉(zhuǎn)換就可以獲取你存儲其中的對象和變量值。
ViewState只能在一個頁面上傳值(session可跨多個頁面?zhèn)髦担琕iewState只是在當(dāng)前page內(nèi)有效,關(guān)了當(dāng)前頁,再重新打開,ViewState所保存的值也就消失了。需要在用戶訪問一個頁面時保持一個變量的值,并隨時改變它的值,用ViewState好些。ViewState是用來同步客戶端與服務(wù)端的變量狀態(tài)的!當(dāng)有兩個用戶對同一頁面進(jìn)行操作時,若使用Static出現(xiàn)了數(shù)據(jù)張冠李戴的嚴(yán)重錯誤時,改為ViewState后就會一切正常了。
開發(fā)C/S模式的系統(tǒng)和開發(fā)B/S模式的系統(tǒng)有很大的不同。因此我們一定要根據(jù)不同情況正確理解各種變量的作用域和生存期,以便能夠正確使用各種保存數(shù)據(jù)的方法而不至于出現(xiàn) 錯誤。
后來一查是在程序中設(shè)了靜態(tài)變量的關(guān)系,由于靜態(tài)變量是全局的所以會出錯。
對此問題進(jìn)行學(xué)習(xí)一下(下列內(nèi)容來自各個網(wǎng)頁精華,由于截取不同網(wǎng)頁,如有侵權(quán),請和我聯(lián)系):
利用asp.net 開發(fā)基于B/S模式的應(yīng)用系統(tǒng),經(jīng)常會遇到同一頁面類的各函數(shù)成員之間、 同一會話各頁面之間、不同機器各用戶頁面之間的傳值問題,即要解決數(shù)據(jù)共享的問題。這可以選擇使用Application、Session、cookie、Static、ViewState 等方法實現(xiàn)。
其中Static變量的使用容易出現(xiàn)問題,使用不好會導(dǎo)致數(shù)據(jù)紊亂,給系統(tǒng)造成故障隱患。
用ViewState 作為頁內(nèi)數(shù)據(jù)傳值也是一種較好的選擇 。在C#中,static變量表示該變量屬于類,而不是類的實例。可以說是該類的所有實例共享一個static變量。
asp.net的頁面就是一個類,我們訪問一個頁面。就會在服務(wù)器上實例化一個該類的實例,來響應(yīng)我們的請求。
“所有實例共享一個static變量” 這就意味著,所有的客戶端訪問到的asp.net頁面中static變量都是同一個變量。
由于我們每次訪問asp.net頁面都是一個全新的對象,而不是我們上一次訪問的對象。所以上次頁面訪問時我們對頁面中變量的改動都沒有保留。
遇到這個問題的時候,很多初學(xué)者的直覺就是將這個變量申明為static,自己在測試的時候發(fā)現(xiàn)還真的保留住了頁面的狀態(tài)。竊喜之余沒有發(fā)現(xiàn)這又有引入了另外一個錯誤。因為你要的只是頁面能保留住狀態(tài),而這個狀態(tài)是針對一個客戶端的(session的效果)。而得到的結(jié)果是只要一個客戶端改變了該值所有的其他客戶端都受到了影響(如同Applicatin的效果)。
究其原因這還要從Asp.net的運行機制談起。在C/S模式軟件開發(fā)過程中,我們通常不會關(guān)心應(yīng)用程序是在哪里運行的,變量存放在哪里,客戶端程序就運行在客戶端,服務(wù)器端程序就運行在服務(wù)器端,一般情況下,二者除了數(shù)據(jù)庫中的數(shù)據(jù)外基本沒有其他共享的問題。 所以這時客戶端的用戶大可放心的使用static變量,因為它們就存放在客戶端程序中。
于是我們就習(xí)慣的在做B/S模式的頁面時也用static變量,殊不知Asp.net中的static已 不同于C/S中的static。是因為在Asp.net中所有的用戶將使用同一個static變量。這就意味 著每一個使用該頁面的用戶對該變量的操作將會影響到其他用戶。
解決的辦法之一是可以選擇Asp.net提供的ViewState對象。ViewState對象可以用來保存頁面中的各種變量,甚至是對象。“有些數(shù)據(jù)可以直接保存到ViewState中,諸如字符串 、整數(shù)、布爾、數(shù)組里表、哈希表等。”
“所謂ViewState,實際上是一些鍵值對,ASP.NET通過它維護網(wǎng)頁和服務(wù)器的狀態(tài),并將ViewState封裝成一個或幾個隱藏的表單域傳遞到客戶端。而客戶端提交時,ViewState也 將被提交到服務(wù)器端。這樣后續(xù)的請求可以獲得上一次請求的狀態(tài)。”
只要用變量名稱做索引,如ViewState[“Var ”], 就可以存取變量Var的值,而不管Var是普通變量,還是對象,甚至是內(nèi)存中的一張DataTabl e。服務(wù)器端會為每個連接到該頁面的用戶分別建立一個ViewState,所以ViewState相當(dāng)于 頁面級的Session。相當(dāng)于頁面全局變量,但是一旦退出當(dāng)前頁面,它就會丟失。
ViewState的用法很簡單,如下所示:
1、保存變量到ViewState中(賦值):
ViewState[“times”]=times; //存放普通變量times
ViewState[“Orders”]=dtOrders; //存放DataTable型對象dtOrders
ViewState ["aa"] ="123";
2、讀出ViewState中的值(取值):
times = (int)ViewState[“times”];
dtOrders = (DataTable)ViewState[“Orders”]; string bb = ViewState["aa"].ToString();
讀出變量的值時要進(jìn)行強制類型轉(zhuǎn)換,這是因為當(dāng)變量(不管是int型的普通變量times ,還是DataTable型的對象dtOrders)被存放到ViewState中后統(tǒng)統(tǒng)按Object類型存放。所以 當(dāng)我們從ViewState取出時,一定要轉(zhuǎn)換成相應(yīng)的類型,否則就會報錯。在變量保存到ViewS tate中時,系統(tǒng)會自動轉(zhuǎn)換。
這不是說static型變量就沒用了,在C#中用static聲明的類不用實例化直接使用。正是由于所有用戶共享服務(wù)器端的同一個static變量,所以可以用static型對象來存取一些公用的處理模塊,比如類型轉(zhuǎn)換、變量驗證等工作。所以要根據(jù)具體情況而定。
還有一點需要注意:如果在頁面中多個過程要共享一個對象或變量,我們在頁面類的開始部分定義一個頁面級的全局變量是不行的,static本來可以,但上面說了這種類型的變量不安全,所以這時就可以用ViewState。
ViewState是將數(shù)據(jù)存入到頁面隱藏控件里,不再占用服務(wù)器資源,因此, 我們可以將一 些需要服務(wù)器"記住"的變量和對象保存到viewstate里面。viewstate并不能存儲所有的.net 類型數(shù)據(jù),它僅僅支持String、Integer、Boolean、Array、ArrayList、Hashtable 以及自定義的一些類型。
ViewState 常用于保存單個用戶的狀態(tài)信息,生存期等于頁面的生存期。viewstate是 在本頁面之內(nèi)各函數(shù)間進(jìn)行傳值的 , 至于為什么要使用這種方法是因為在一個事件發(fā)生之后 , 頁面可能會刷新 , 如果定義全局變量會被清零 , 所以要使用 viewstate保持?jǐn)?shù)據(jù),任何事物都有兩面性, 因為ViewState變量在客戶端實際上是用<input type=“hidden ” value=“ADFAIB3P234P-AFAFAF……”/>保存的一個對象,這樣如果要保存的是個對象, 甚 至是個很復(fù)雜的對象(如DataTable),這樣以來就會增加網(wǎng)絡(luò)傳輸?shù)呢?fù)擔(dān)。 使用viewstat e會增加頁面html的輸出量,占用更多的帶寬,這一點是需要慎重考慮的。另外, 由于所有的v iewstate都是存儲在一個隱藏域里面,用戶可以很容易的通過查看源碼來看到這個經(jīng)過base6 4編碼的值,然后再經(jīng)過轉(zhuǎn)換就可以獲取你存儲其中的對象和變量值。
ViewState只能在一個頁面上傳值(session可跨多個頁面?zhèn)髦担琕iewState只是在當(dāng)前page內(nèi)有效,關(guān)了當(dāng)前頁,再重新打開,ViewState所保存的值也就消失了。需要在用戶訪問一個頁面時保持一個變量的值,并隨時改變它的值,用ViewState好些。ViewState是用來同步客戶端與服務(wù)端的變量狀態(tài)的!當(dāng)有兩個用戶對同一頁面進(jìn)行操作時,若使用Static出現(xiàn)了數(shù)據(jù)張冠李戴的嚴(yán)重錯誤時,改為ViewState后就會一切正常了。
開發(fā)C/S模式的系統(tǒng)和開發(fā)B/S模式的系統(tǒng)有很大的不同。因此我們一定要根據(jù)不同情況正確理解各種變量的作用域和生存期,以便能夠正確使用各種保存數(shù)據(jù)的方法而不至于出現(xiàn) 錯誤。