西西軟件下載最安全的下載網(wǎng)站、值得信賴(lài)的軟件下載站!

首頁(yè)編程開(kāi)發(fā)ASP.NET → ASP.NET編程中Web頁(yè)面幾種狀態(tài)管理總結(jié)

ASP.NET編程中Web頁(yè)面幾種狀態(tài)管理總結(jié)

相關(guān)軟件相關(guān)文章發(fā)表評(píng)論 來(lái)源:西西整理時(shí)間:2012/11/21 8:45:07字體大。A-A+

作者:西西點(diǎn)擊:0次評(píng)論:0次標(biāo)簽: Cookie Session

  • 類(lèi)型:站長(zhǎng)工具大。5KB語(yǔ)言:中文 評(píng)分:7.5
  • 標(biāo)簽:
立即下載

由于HTTP協(xié)議的無(wú)狀態(tài)特性,導(dǎo)致在ASP.NET編程中,每個(gè)請(qǐng)求都會(huì)在服務(wù)端從頭到執(zhí)行一次管線(xiàn)過(guò)程, 對(duì)于ASP.NET頁(yè)面來(lái)說(shuō),Page對(duì)象都會(huì)重新創(chuàng)建,所有控件以及內(nèi)容都會(huì)重新生成, 因此,如果希望上一次的頁(yè)面狀態(tài)能夠在后續(xù)頁(yè)面中保留,則必需引入狀態(tài)管理功能。

ASP.NET為了實(shí)現(xiàn)狀態(tài)管理功能,提供了8種方法,可幫助我們?cè)陧?yè)面之間或者整個(gè)用戶(hù)會(huì)話(huà)期間保留狀態(tài)數(shù)據(jù)。 這些方法分為二類(lèi):視圖狀態(tài)、控件狀態(tài)、隱藏域、Cookie 和查詢(xún)字符串會(huì)以不同方式將數(shù)據(jù)發(fā)送到客戶(hù)端上。 而應(yīng)用程序狀態(tài)、會(huì)話(huà)狀態(tài)和配置文件屬性(Profile)則會(huì)將數(shù)據(jù)存儲(chǔ)到服務(wù)端。 雖然每種方法都有不同的優(yōu)點(diǎn)和缺點(diǎn),對(duì)于小的項(xiàng)目來(lái)說(shuō),可以選擇自己認(rèn)為最容易使用的方法, 然而,對(duì)于有著較高要求的程序,尤其是對(duì)于性能與擴(kuò)展性比較關(guān)注的程序來(lái)說(shuō), 選擇不同的方法最終導(dǎo)致的差別可能就非常大了。

在這篇博客中,我將談?wù)勛约簩?duì)ASP.NET狀態(tài)管理方面的一些看法。
注意:本文的觀點(diǎn)可能并不合適開(kāi)發(fā)小型項(xiàng)目,因?yàn)槲谊P(guān)注的不是易用性。

hidden-input( 隱藏域

hidden-input 這個(gè)名字我是取的,表示所有type="hidden"的input標(biāo)簽元素。 在中文版的MSDN中,也稱(chēng)之為 隱藏域 。 hidden-input通常存在于HTML表單之內(nèi),它不會(huì)顯示到頁(yè)面中, 但可以隨表單一起提交,因此,經(jīng)常用于維護(hù)當(dāng)前頁(yè)面的相關(guān)狀態(tài),在服務(wù)端我們可以使用Request.Form[]來(lái)訪問(wèn)這些數(shù)據(jù)。

一般說(shuō)來(lái),我通常使用hidden-input來(lái)保存一些中間結(jié)果,用于在多次提交中維持一系列狀態(tài), 或者用它來(lái)保存一些固定參數(shù)用來(lái)提交給其它頁(yè)面(或網(wǎng)站)。 在這些場(chǎng)景中,我不希望用戶(hù)看到這些數(shù)據(jù),因此,使用hidden-input是比較方便的。

關(guān)于表單的更多介紹可參考我的博客:細(xì)說(shuō) Form (表單)

在ASP.NET WebForm框架中,我們可以使用HiddenField控件來(lái)創(chuàng)建一個(gè)hidden-input控件,并可以在服務(wù)端操作它, 還可以直接以手寫(xiě)的方式使用隱藏域,例如:

<input type="hidden" name="hidden-1" value="aaaaaaa" />
<input type="hidden" name="hidden-2" value="bbbbbbb" />
<input type="hidden" name="hidden-3" value="ccccccc" />

另外,我們還可以調(diào)用ClientScript.RegisterHiddenField()方法來(lái)創(chuàng)建隱藏域:

ClientScript.RegisterHiddenField("hidden-4", "ddddddddd");

輸出結(jié)果:

<input type="hidden" name="hidden-4" id="hidden-4" value="ddddddddd" />

這三種方法對(duì)于生成的HTML代碼來(lái)說(shuō),主要差別在于它們出現(xiàn)位置不同:
1. HiddenField控件:由HiddenField的出現(xiàn)位置來(lái)決定(在form內(nèi)部)。
2. RegisterHiddenField方法:在form標(biāo)簽的開(kāi)頭位置。
3. hidden-input:你寫(xiě)在哪里就是哪里。

優(yōu)點(diǎn):
1. 不需要任何服務(wù)器資源:隱藏域隨頁(yè)面一起發(fā)送到客戶(hù)端。
2. 廣泛的支持:幾乎所有瀏覽器和客戶(hù)端設(shè)備都支持具有隱藏域的表單。
3. 實(shí)現(xiàn)簡(jiǎn)單:隱藏域是標(biāo)準(zhǔn)的 HTML 控件,不需要復(fù)雜的編程邏輯。

缺點(diǎn):
1. 不能在多頁(yè)面跳轉(zhuǎn)之間維持狀態(tài)。
2. 用戶(hù)可見(jiàn),保存敏感數(shù)據(jù)時(shí)需要加密。

QueryString

查詢(xún)字符串是存在于 URL 結(jié)尾的一段數(shù)據(jù)。下面是一個(gè)典型的查詢(xún)字符串示例(紅色部分文字):

http://www.abc.com/demo.aspx?k1=aaa&k2=bbb&k3=ccc

查詢(xún)字符串經(jīng)常用于頁(yè)面的數(shù)據(jù)過(guò)濾,例如:
1. 給列表頁(yè)面增加分頁(yè)參數(shù),list.aspx?page=2
2. 給列表頁(yè)面增加過(guò)慮范圍,Product.aspx?categoryId=5
3. 顯示特定記錄,ProductInfo.aspx?page=3

關(guān)于查詢(xún)字符串的用法,我補(bǔ)充二點(diǎn):
1. 可以調(diào)用HttpUtility.ParseQueryString()來(lái)解析查詢(xún)字符串。
2. 允許參數(shù)名重復(fù):list.aspx?page=2&page=3,因此在修改URL參數(shù)時(shí),使用替換方式而不是追加。
  關(guān)于參數(shù)重名的讀取問(wèn)題,請(qǐng)參考我的博客:細(xì)說(shuō) Request[]與Request.Params[]

優(yōu)點(diǎn):
1. 不需要任何服務(wù)器資源:查詢(xún)字符串的數(shù)據(jù)包含在每個(gè)URL中。
2. 廣泛的支持:幾乎所有的瀏覽器和客戶(hù)端設(shè)備均支持使用查詢(xún)字符串傳遞參數(shù)值。
3. 實(shí)現(xiàn)簡(jiǎn)單:在服務(wù)端直接訪問(wèn)Request.QueryString[]可讀取數(shù)據(jù)。
4. 頁(yè)面?zhèn)髦岛?jiǎn)單:<a href="url">或者 Response.Redirect(url) 都可以實(shí)現(xiàn)。

缺點(diǎn):
1. 有長(zhǎng)度限制。
2. 用戶(hù)可見(jiàn),不能保存敏感數(shù)據(jù)。

Cookie

由于HTTP協(xié)議是無(wú)狀態(tài)的,對(duì)于一個(gè)瀏覽器發(fā)出的多次請(qǐng)求,web服務(wù)器無(wú)法區(qū)分它們是不是來(lái)源于同一個(gè)瀏覽器。所以,需要額外的數(shù)據(jù)用于維護(hù)會(huì)話(huà)。 Cookie 正是這樣的一段隨HTTP請(qǐng)求一起被傳遞的額外數(shù)據(jù)。 Cookie 是一小段文本信息,它的工作方式就是伴隨著用戶(hù)請(qǐng)求和頁(yè)面在 Web 服務(wù)器和瀏覽器之間傳遞。Cookie 包含每次用戶(hù)訪問(wèn)站點(diǎn)時(shí) Web 應(yīng)用程序都可以讀取的信息。

與hidden-input, QueryString相比,Cookie有更多的屬性,許多瀏覽器可以直接查看這些信息:

由于Cookie擁有這些屬性,因此在客戶(hù)端狀態(tài)管理中可以實(shí)現(xiàn)更多的功能,尤其是在實(shí)現(xiàn)客戶(hù)端會(huì)話(huà)方面具有不可替代的作用。

關(guān)于Cookie的更多講解,請(qǐng)參考我的另一篇博客:細(xì)說(shuō)Cookie

優(yōu)點(diǎn):
1. 可配置到期規(guī)則:Cookie可以在客戶(hù)端長(zhǎng)期存在,也可以在瀏覽器關(guān)閉時(shí)清除。
2. 不需要任何服務(wù)器資源:Cookie 存儲(chǔ)在客戶(hù)端。
3. 簡(jiǎn)單性:Cookie 是一種基于文本的輕量結(jié)構(gòu),包含簡(jiǎn)單的鍵值對(duì)。
4. 數(shù)據(jù)持久性:與其它的客戶(hù)端狀態(tài)數(shù)據(jù)相比,Cookie可以實(shí)現(xiàn)長(zhǎng)久保存。 
5. 良好的擴(kuò)展性:Cookie的讀寫(xiě)要經(jīng)過(guò)ASP.NET管線(xiàn),擁有無(wú)限的擴(kuò)展性。

這里我要解釋一下Cookie 【良好的擴(kuò)展性】是個(gè)什么概念,比如:
1. 我可以實(shí)現(xiàn)把Cookie保存到數(shù)據(jù)庫(kù)中而不需要修改現(xiàn)有的項(xiàng)目代碼。
2. 把SessionId這樣由ASP.NET產(chǎn)生的臨時(shí)Cookie讓它變成持久保存。

缺點(diǎn):
1. 大小受到限制。
2. 增加請(qǐng)求頭長(zhǎng)度。
3. 用戶(hù)可見(jiàn),保存敏感數(shù)據(jù)時(shí)需要加密。

ApplicationState

應(yīng)用程序狀態(tài)是指采用HttpApplicationState實(shí)現(xiàn)的狀態(tài)維持方式,使用代碼如下:

Application.Lock();
Application["PageRequestCount"] = ((int)Application["PageRequestCount"]) + 1;
Application.UnLock();

對(duì)于這種方法,我不建議使用,因?yàn)椋?br />1. 與使用靜態(tài)變量差不多,直接使用靜態(tài)變量可以不需要字典查找。
2. 選擇強(qiáng)類(lèi)型的集合或者變量可以避免裝箱拆箱。

ViewState,ControlState

視圖狀態(tài),控件狀態(tài),二者是類(lèi)似,在頁(yè)面中表現(xiàn)為一個(gè)hidden-input元素:

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="......................" />

控件狀態(tài)是ASP.NET 2.0中引入,與視圖狀態(tài)相比,它不允許關(guān)閉。
由于它們使用方式一致,而且視圖狀態(tài)是基于控件狀態(tài)的實(shí)現(xiàn)邏輯,所以我就不區(qū)分它們了。

在ASP.NET的早期,微軟為了能幫助廣大開(kāi)發(fā)人員提高開(kāi)發(fā)效率,引用入一大批的服務(wù)端控件,并為了能將事件編程機(jī)制引入ASP.NET中,又發(fā)明了ViewState。

這種方式雖然可以簡(jiǎn)化開(kāi)發(fā)工作量,然而卻有一些限制和缺點(diǎn):
1. 視圖狀態(tài)的數(shù)據(jù)只能用于回發(fā)(postback)。
2. 視圖狀態(tài)的【濫用】容易導(dǎo)致生成的HTML較大,這會(huì)引起一個(gè)惡性循環(huán):
  a. 過(guò)大的ViewState在序列化過(guò)程中會(huì)消耗較多的服務(wù)器CPU資源,
  b. 過(guò)大的ViewState最終生成的HTML輸出也會(huì)很大,它會(huì)浪費(fèi)服務(wù)端網(wǎng)絡(luò)資源,
  c. 過(guò)大的ViewState輸出導(dǎo)致表單在下次提交時(shí),會(huì)占用客戶(hù)端網(wǎng)絡(luò)資源。
  d. 過(guò)大的ViewState數(shù)據(jù)上傳到服務(wù)端后,反序列化又會(huì)消耗較多的服務(wù)器CPU資源。
  因此,整個(gè)交互過(guò)程中,用戶(hù)一直在等待,用戶(hù)體驗(yàn)極差。

在ASP.NET興起的年代,ViewState絕對(duì)是個(gè)了不起的發(fā)明。
然而,現(xiàn)在很多關(guān)于ASP.NET性能優(yōu)化的方法中,都會(huì)將【關(guān)閉ViewState】放在頭條位置。
為什么會(huì)這樣呢,大家可以自己思考一下了。

有些人認(rèn)為:我現(xiàn)在做的程序只是在局域網(wǎng)內(nèi)使用,使用ViewState完全沒(méi)有問(wèn)題!
然而,那些人或許沒(méi)有想過(guò):
1. 未來(lái)用戶(hù)可能會(huì)把它部署在互聯(lián)網(wǎng)上運(yùn)行(對(duì)于產(chǎn)品來(lái)說(shuō)就是遇到大客戶(hù)了)。
2. 項(xiàng)目早期的設(shè)計(jì)與規(guī)劃,對(duì)后期的開(kāi)發(fā)與維護(hù)來(lái)說(shuō),影響是巨大的,因?yàn)樵S多基礎(chǔ)部分通常是在早期開(kāi)發(fā)的。
當(dāng)這二種情況的任何一種發(fā)生時(shí),想再禁用ViewState,可能已經(jīng)晚了。

對(duì)于視圖狀態(tài),我認(rèn)為它解決的問(wèn)題比它引入的問(wèn)題要多要復(fù)雜,
因此,我不想花時(shí)間整理它的優(yōu)缺點(diǎn),我只想說(shuō)一句:把它關(guān)了,在web.config中關(guān)了。

另外,我不排斥使用服務(wù)器控件,我認(rèn)為:你可以使用服務(wù)端控件顯示數(shù)據(jù),但不要用它處理回發(fā)。

如果你仍然認(rèn)為視圖狀態(tài)是不可缺少的,那我還是建議你看看ASP.NET MVC框架,看看沒(méi)有視圖狀態(tài)是不是照樣可以寫(xiě)ASP.NET程序。

Session是ASP.NET實(shí)現(xiàn)的一種服務(wù)端會(huì)話(huà)技術(shù),它允許我們方便地在服務(wù)端保存與用戶(hù)有關(guān)的會(huì)話(huà)數(shù)據(jù)。

我認(rèn)為Session只有一個(gè)優(yōu)點(diǎn):最簡(jiǎn)單的服務(wù)端會(huì)話(huà)實(shí)現(xiàn)方式。

缺點(diǎn):
1. 當(dāng)mode="InProc"時(shí),容易丟失數(shù)據(jù),為什么?因?yàn)榫W(wǎng)站會(huì)因?yàn)楦鞣N原因重啟。
2. 當(dāng)mode="InProc"時(shí),Session保存的東西越多,就越占用服務(wù)器內(nèi)存,對(duì)于用戶(hù)在線(xiàn)人數(shù)較多的網(wǎng)站,服務(wù)器的內(nèi)存壓力會(huì)比較大。
3. 當(dāng)mode="InProc"時(shí),程序的擴(kuò)展性會(huì)受到影響,原因很簡(jiǎn)單:服務(wù)器的內(nèi)存不能在多臺(tái)服務(wù)器間共享。
4. 當(dāng)采用進(jìn)程外模式時(shí),在每次請(qǐng)求中,不管你用不用會(huì)話(huà)數(shù)據(jù),所有的會(huì)話(huà)數(shù)據(jù)都為你準(zhǔn)備好了(反序列化),這其實(shí)很是浪費(fèi)資源的。
5. 如果你沒(méi)有關(guān)閉Session,SessionStateModule就一直在工作中,尤其是全采用默認(rèn)設(shè)置時(shí),會(huì)對(duì)每個(gè)請(qǐng)求執(zhí)行一系列的調(diào)用,浪費(fèi)資源。
6. 阻塞同一客戶(hù)端發(fā)起的多次請(qǐng)求(默認(rèn)方式)。
7. 無(wú)Cookie會(huì)話(huà)可能會(huì)丟失數(shù)據(jù)(重新生成已過(guò)期的會(huì)話(huà)標(biāo)識(shí)符)。

Session的這些缺點(diǎn)也提醒我們:
1. 當(dāng)網(wǎng)站的在線(xiàn)人數(shù)較多時(shí),一定不要用Session保存較大的對(duì)象。
2. 在密集型的AJAX型網(wǎng)站或者大量使用iframe的網(wǎng)站中,要關(guān)注Session可能引起的服務(wù)端阻塞問(wèn)題。
3. 當(dāng)采用進(jìn)程外模式時(shí),不需要訪問(wèn)Session的頁(yè)面,一定要關(guān)閉,否則會(huì)浪費(fèi)服務(wù)器資源。

如果想了解更多的Session特點(diǎn),以及我對(duì)Session的看法,可以瀏覽我的博客:Session,有沒(méi)有必要使用它?

Session的本質(zhì)有二點(diǎn):
1. SessionId + 服務(wù)端字典:服務(wù)端字典保存了某個(gè)用戶(hù)的所有會(huì)話(huà)數(shù)據(jù)。
2. 用SessionId識(shí)別不同的客戶(hù)端:SessionId通常以Cookie形式發(fā)送到客戶(hù)端。

我認(rèn)為了解Sesssion本質(zhì)非常有用,因?yàn)榭梢越梃b并實(shí)現(xiàn)自己的服務(wù)端會(huì)話(huà)方法。

關(guān)于Session我還想說(shuō)一點(diǎn):
有些新手喜歡用Session來(lái)實(shí)現(xiàn)身份認(rèn)證功能,這是一種【不正確】的方法。
如果你的ASP.NET應(yīng)用程序需要身份認(rèn)證功能,請(qǐng)使用 Forms身份認(rèn)證 或者 Windows身份認(rèn)證

Profile 在中文版的MSDN中被稱(chēng)為 配置文件屬性,這個(gè)功能是在 ASP.NET 2.0 中引入的。

ASP.NET提供這個(gè)功能主要是為了簡(jiǎn)化與用戶(hù)相關(guān)的個(gè)性化信息的讀寫(xiě)方式。
簡(jiǎn)化主要體現(xiàn)在3個(gè)方面:
1. 自動(dòng)與某個(gè)用戶(hù)關(guān)聯(lián),已登錄用戶(hù)或者未登錄都支持。
2. 不需要我們?cè)O(shè)計(jì)用戶(hù)的個(gè)性化信息的保存表結(jié)構(gòu),只要修改配置文件就夠了。
3. 不需要我們實(shí)現(xiàn)數(shù)據(jù)的加載與保存邏輯,ASP.NET框架替我們實(shí)現(xiàn)好了。

為了使用Profile,我們首先在web.config中定義所需要的用戶(hù)個(gè)性化信息:

<profile>
    <properties>
        <add name="Address"/>
        <add name="Tel"/>
    </properties>
</profile>

然后,就可以在頁(yè)面中使用了:

為什么會(huì)這樣呢?
原因是ASP.NET已經(jīng)根據(jù)web.config為我們創(chuàng)建了一個(gè)新類(lèi)型:

using System;
using System.Web.Profile;

public class ProfileCommon : ProfileBase
{
    public ProfileCommon();

    public virtual string Address { get; set; }
    public virtual string Tel { get; set; }

    public virtual ProfileCommon GetProfile(string username);
}

有了這個(gè)類(lèi)型后,當(dāng)我們?cè)L問(wèn)HttpContext.Profile屬性時(shí),ASP.NET會(huì)創(chuàng)建一個(gè)ProfileCommon的實(shí)例。 也正是由于Profile的強(qiáng)類(lèi)型機(jī)制,在使用Profile時(shí)才會(huì)有智能提示功能。

如果我們希望為未登錄的匿名用戶(hù)也提供這種支持,需要將配置修改成:

<profile>
    <properties>
        <add name="Address" allowAnonymous="true" />
        <add name="Tel" allowAnonymous="true"/>
    </properties>
</profile>
<anonymousIdentification enabled="true" />

Profile中的每個(gè)屬性還允許指定類(lèi)型和默認(rèn)值,以及序列化方式,因此,擴(kuò)展性還是比較好的。

盡管Profile看上去很美,然而,使用Profile的人卻很少。
比如我就不用它,我也沒(méi)見(jiàn)有人有過(guò)它。
為什么會(huì)這樣?

我個(gè)人認(rèn)為:它與MemberShip一樣,是個(gè)雞肋。
通常說(shuō)來(lái),我們會(huì)為用戶(hù)信息創(chuàng)建一張User表,增加用戶(hù)信息時(shí),會(huì)通過(guò)增加字段的方式解決。
我認(rèn)為這樣集中的數(shù)據(jù)才會(huì)更好,而不是說(shuō),有一部分?jǐn)?shù)據(jù)由我維護(hù),另一部分?jǐn)?shù)據(jù)由ASP.NET維護(hù)。

另一個(gè)特例是:我們根本不創(chuàng)建User表,直接使用MemberShip,那么Profile用來(lái)保存MemberShip沒(méi)有信息是有必要的。

還是給Profile做個(gè)總結(jié)吧:
優(yōu)點(diǎn):使用簡(jiǎn)單。
缺點(diǎn):不實(shí)用。

各種狀態(tài)管理的對(duì)比與總結(jié)

前面分別介紹了ASP.NET的8種狀態(tài)管理技術(shù),這里打算給它們做個(gè)總結(jié)。

 客戶(hù)端服務(wù)端
數(shù)據(jù)安全性
數(shù)據(jù)長(zhǎng)度限制受硬件限制
占用服務(wù)器資源
集群擴(kuò)展性

表格中主要考察了數(shù)據(jù)保存與服務(wù)端水平擴(kuò)展的相關(guān)重要指標(biāo)。

下面我來(lái)解釋表格的結(jié)果。
1. 客戶(hù)端方式的狀態(tài)數(shù)據(jù)(hidden-input, QueryString, Cookie):
  a. 數(shù)據(jù)對(duì)用戶(hù)來(lái)說(shuō),可見(jiàn)可修改,因此數(shù)據(jù)不安全。
  b. QueryString, Cookie 都有長(zhǎng)度限制。
  c. 數(shù)據(jù)在客戶(hù)端,因此不占用服務(wù)端資源。這個(gè)特性對(duì)于在線(xiàn)人數(shù)很多的網(wǎng)站非常重要。
  d. 數(shù)據(jù)在客戶(hù)端,因此和服務(wù)端沒(méi)有耦合關(guān)系,WEB服務(wù)器可以更容易實(shí)現(xiàn)水平擴(kuò)展。

2. 服務(wù)端方式的狀態(tài)數(shù)據(jù)(ApplicationState,ViewState,ControlState,Session,Profile):
  a. 數(shù)據(jù)對(duì)用戶(hù)不可見(jiàn),因此安全性好。(ApplicationState,Session,Profile)
  b. 數(shù)所長(zhǎng)度只受硬件限制,因此,對(duì)于在線(xiàn)人數(shù)較多的網(wǎng)站,需謹(jǐn)慎選擇。
  c. 對(duì)于存放在內(nèi)存中的狀態(tài)數(shù)據(jù),由于不能共享內(nèi)存,因此會(huì)限制水平擴(kuò)展能力。
  d. 如果狀態(tài)數(shù)據(jù)保存到一臺(tái)機(jī)器,會(huì)有單點(diǎn)失敗的可能,也會(huì)限制了水平擴(kuò)展能力。

從這個(gè)表格我們還可以得到以下結(jié)論:
1. 如果很關(guān)注數(shù)據(jù)的安全性,應(yīng)該首選服務(wù)端的狀態(tài)管理方法。
2. 如果你關(guān)注服務(wù)端的水平擴(kuò)展性,應(yīng)該首選客戶(hù)端的狀態(tài)管理方法。

會(huì)話(huà)狀態(tài)的選擇

接下來(lái),我們?cè)賮?lái)看看會(huì)話(huà)狀態(tài),它與狀態(tài)管理有著一些關(guān)系,屬于比較類(lèi)似的概念。

談到會(huì)話(huà)狀態(tài),首先我要申明一點(diǎn):會(huì)話(huà)狀態(tài)與狀態(tài)不是一回事。

本文前面所說(shuō)的狀態(tài)分為二種:
1. 頁(yè)面之間的狀態(tài)。
2. 應(yīng)用程序范圍內(nèi)的狀態(tài)。

而會(huì)話(huà)狀態(tài)是針對(duì)某個(gè)用戶(hù)來(lái)說(shuō),他(她)在多次操作之間的狀態(tài)。
在用戶(hù)的操作期間,有可能狀態(tài)需要在頁(yè)面之間持續(xù)使用,
也有可能服務(wù)端程序做過(guò)重啟,但數(shù)據(jù)仍然有效。
因此,這種狀態(tài)數(shù)據(jù)更持久。

在ASP.NET中,使用會(huì)話(huà)狀態(tài)有二個(gè)選擇:Session 或者 Cookie 。
前者由ASP.NET實(shí)現(xiàn),并有可能依賴(lài)后者。
后者則由瀏覽器實(shí)現(xiàn),ASP.NET提供讀寫(xiě)方法。

那么到底選擇哪個(gè)呢?
如果你要問(wèn)我這個(gè)問(wèn)題,我肯定會(huì)說(shuō):我選 Cookie !

下面是我選擇Cookie實(shí)現(xiàn)會(huì)話(huà)狀態(tài)的理由:
1. 不會(huì)有服務(wù)端阻塞問(wèn)題。
2. 不占用服務(wù)端資源。
3. 水平擴(kuò)展沒(méi)有限制。
4. 也支持過(guò)期設(shè)置,而且更靈活。
5. 可以在客戶(hù)端直接使用會(huì)話(huà)數(shù)據(jù)。
6. 可以實(shí)現(xiàn)更靈活的會(huì)話(huà)數(shù)據(jù)加載策略。
7. 擴(kuò)展性較好(源于ASP.NET管線(xiàn)的擴(kuò)展性)

如果選擇使用Cookie實(shí)現(xiàn)會(huì)話(huà)狀態(tài),有3點(diǎn)需要特別注意:
1. 不建議保存敏感數(shù)據(jù),除非已加密。
2. 只適合保存短小簡(jiǎn)單的數(shù)據(jù)。
3. 如果會(huì)話(huà)數(shù)據(jù)較大,可以在客戶(hù)端保存用戶(hù)標(biāo)識(shí),由服務(wù)端實(shí)現(xiàn)數(shù)據(jù)的加載保存邏輯。

或許有些人認(rèn)為:每種技術(shù)都有它們的優(yōu)缺點(diǎn),有各自的適用領(lǐng)域。
我表示贊同這句話(huà)。
但是,我們要清楚一點(diǎn):每個(gè)項(xiàng)目的規(guī)模不一樣,性能以及擴(kuò)展性要求也不同。
對(duì)于一個(gè)小的項(xiàng)目來(lái)說(shuō),選擇什么方法都不是問(wèn)題,
但是,對(duì)于規(guī)模較大的項(xiàng)目,我們一定需要取舍。
取舍的目標(biāo)是:包裝越少越好,因?yàn)槿思易隽诉^(guò)多的包裝,就會(huì)有較多的限制,
所以,不要只關(guān)注現(xiàn)在的調(diào)用是否方便,其實(shí)只要你愿意包裝,你也可以讓復(fù)雜的調(diào)用簡(jiǎn)單化。

改變開(kāi)發(fā)方式,發(fā)現(xiàn)新方法

回想一下:為什么在ASP.NET中需要狀態(tài)管理?
答:因?yàn)榕cHTTP協(xié)議有關(guān),服務(wù)端沒(méi)有保存每個(gè)請(qǐng)求的上次頁(yè)面狀態(tài)。

為什么Windows計(jì)算器(這類(lèi))程序不用考慮會(huì)話(huà)問(wèn)題呢?
答:因?yàn)檫@類(lèi)程序的界面不需要重新生成,任何變量都可表示狀態(tài)。

再來(lái)看這樣一個(gè)場(chǎng)景:

圖片左邊是一個(gè)列表頁(yè)面,允許調(diào)整每條記錄的優(yōu)先級(jí),但是有2個(gè)要求:
1. 在移動(dòng)每條記錄時(shí),必須輸入一個(gè)調(diào)整理由。
2. 只要輸入理由后,那條記錄可以任意調(diào)整多次。

顯然,完成這個(gè)任務(wù)必須要有狀態(tài)才能實(shí)現(xiàn)。

面對(duì)這個(gè)問(wèn)題,你可以思考一下:選擇哪種ASP.NET支持的狀態(tài)管理方法都很麻煩。

怎么辦?

我的解決方法:創(chuàng)建一個(gè)JavaScript數(shù)組,用每個(gè)數(shù)組元素保存每條記錄的狀態(tài),
所有用戶(hù)交互操作用AJAX方式實(shí)現(xiàn),這樣頁(yè)面不會(huì)刷新,JavaScript變量中的狀態(tài)一直有效。
因此,很容易就能解決這個(gè)問(wèn)題。

這個(gè)案例也提醒我們:當(dāng)發(fā)現(xiàn)ASP.NET提供的狀態(tài)管理功能全部不合適時(shí), 我們需要改變開(kāi)發(fā)方式了。

為什么WEB編程都有【無(wú)狀態(tài)】問(wèn)題,而桌面程序沒(méi)有?
我認(rèn)為與HTTP協(xié)議有關(guān),但沒(méi)有絕對(duì)的關(guān)系。
只要你能保證頁(yè)面不刷新,也能像桌面程序那樣,用JavaScript變量就能維護(hù)頁(yè)面狀態(tài)。

    相關(guān)評(píng)論

    閱讀本文后您有什么感想? 已有人給出評(píng)價(jià)!

    • 8 喜歡喜歡
    • 3 頂
    • 1 難過(guò)難過(guò)
    • 5 囧
    • 3 圍觀圍觀
    • 2 無(wú)聊無(wú)聊

    熱門(mén)評(píng)論

    最新評(píng)論

    發(fā)表評(píng)論 查看所有評(píng)論(0)

    昵稱(chēng):
    表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
    字?jǐn)?shù): 0/500 (您的評(píng)論需要經(jīng)過(guò)審核才能顯示)
    推薦文章

    沒(méi)有數(shù)據(jù)

    最新文章
      沒(méi)有數(shù)據(jù)