淺析ASP.NET AJAX
ASP.NET AJAX的許多功能會(huì)要求異步地訪問服務(wù)器端,例如訪問Web Services,Authentication/Profile Services(事實(shí)上和訪問Web Services是相同的機(jī)制)和Partial Rendering。在ASP.NET AJAX中,所有的這些訪問都是通過一個(gè)網(wǎng)絡(luò)訪問的基礎(chǔ)結(jié)構(gòu)來完成的,無一例外。
一般來說,ASP.NET AJAX提供的類已經(jīng)足夠大多數(shù)應(yīng)用的需求,但是在某些特殊情況,可能需要做一些改變。因此,Network Communication Layer提供了一定程度上的擴(kuò)展能力——通過提供自定義的WebRequestExecutor子類來替換默認(rèn)設(shè)置:XMLHttpExecutor。這種改變能夠應(yīng)用于一個(gè)單獨(dú)的WebRequest,也可以對(duì)全局進(jìn)行一個(gè)設(shè)置。這個(gè)我們就能對(duì)于客戶端的行為做一些簡(jiǎn)單的修改和補(bǔ)充。這樣可以說是 Network Communication Layer唯一的“官方”擴(kuò)展點(diǎn),其實(shí)能力有限。至于使用一些靈活的辦法從JavaScript語言特性能上進(jìn)行的修改,在這里就忽略不計(jì)了。
這樣我們就能對(duì)于客戶端的行為做一些簡(jiǎn)單的修改和補(bǔ)充。那么如果對(duì)其進(jìn)行大量的修改會(huì)怎么樣?如果這種修改的確能夠滿足您的需要,當(dāng)然可以??墒沁@樣的話,Partial Rendering就很可能無法實(shí)現(xiàn)了。Partial Rendering的作法是在客戶端和服務(wù)器端產(chǎn)生一個(gè)嚴(yán)謹(jǐn)?shù)膮f(xié)議,用來傳遞和處理大量的數(shù)據(jù)。如果有任何改變被加諸于這些數(shù)據(jù)上,協(xié)議就被破壞了,這個(gè)可以說是ASP.NET AJAX的最重要的功能之一的控件也就失效了。
接下來,我們?cè)敿?xì)了解一下這整個(gè)流程的每個(gè)步驟。
一、創(chuàng)建Sys.Net.WebRequest
這是發(fā)起一個(gè)服務(wù)器請(qǐng)求的***步。首先建立一個(gè)Sys.Net.WebRequest對(duì)象,然后通過addHeader,set_url等方法設(shè)置這個(gè)請(qǐng)求的各個(gè)信息,然后調(diào)用add_complete方法來注冊(cè)complete事件。請(qǐng)注意,這和CTP版本的Sys.Net.WebRequest不同。在CTP版本的Sys.Net.WebRequest中,存在著三個(gè)事件:complete,timeout和aborted,用戶可以有選擇地注冊(cè)這些事件。在RTM的Sys.Net.WebRequest中,三個(gè)事件被合成了一個(gè)complete事件。不管這個(gè)Request的結(jié)果如何,都會(huì)在這個(gè)觸發(fā)這個(gè)事件,用戶需要在響應(yīng)這個(gè)事件的方法里自行根據(jù)得到的Response的信息來分辨這個(gè)請(qǐng)求的狀況。具體的判斷方式稍后再進(jìn)行說明。在創(chuàng)建完 WebRequest對(duì)象后,將調(diào)用它的invoke方法執(zhí)行這個(gè)請(qǐng)求。一個(gè)WebRequest對(duì)象只能被 invoke一次。
二、將WebRequest對(duì)象交給WebRequestManager執(zhí)行
在WebRequest對(duì)象的invoke方法被調(diào)用以后,它會(huì)調(diào)用 “Sys.Net.WebRequestManager.executeRequest(this)”將自身交給全局的 WebRequestManager執(zhí)行。這里的WebRequestManager其實(shí)是Sys.Net._WebRequestManager類的實(shí)例。在初始化環(huán)境的時(shí)候,就會(huì)將這個(gè)類實(shí)例化一個(gè)對(duì)象,賦值到Sys.Net.WebRequestManager變量中,以一個(gè)Singleton的形象供別的方法調(diào)用。它會(huì)在處理Request的過程中在特定的時(shí)刻觸發(fā)一些事件,用戶可以依靠響應(yīng)這些事件來改變Request的行為,例如阻止特定的 Request,或者改變Request的一些屬性等等。
乍看下來,RTM版本中的WebRequestManager和CTP中的 WebRequestManager沒有很大的區(qū)別嘛(引入了幾個(gè)事件除外)。事實(shí)上,個(gè)人認(rèn)為在這個(gè)方面Atlas打了自己一個(gè)耳光。在CTP版本的 WebRequestManager中,對(duì)于管理WebRequest有一套比較復(fù)雜的方法,其理由是能夠更好地利用好瀏覽器的資源,以提高 WebRequest的效率。這就是Atlas對(duì)外一直聲稱的“Client Request Stack”,這一點(diǎn)被當(dāng)作Atlas的重要特點(diǎn)來看待。不過這一點(diǎn)在RTM版本中被取消了,新的WebRequestManager在處理一個(gè) WebRequest對(duì)象的時(shí)候僅僅是觸發(fā)事件,然后簡(jiǎn)單地使用Executor來調(diào)用這個(gè)WebRequest對(duì)象。
下面列舉了調(diào)用了executeRequest方法后的關(guān)鍵邏輯:
1. 檢查WebRequest是否指定了WebRequestExecutor(這可以在構(gòu)造WebRequest的時(shí)候指定)。
2. 如果WebRequest沒有指定WebRequestExecutor,則使用set_executor方法分配默認(rèn)的WebRequestExecutor
3. 構(gòu)造Sys.Net.NetworkRequestEventArgs參數(shù)對(duì)象,觸發(fā)WebRequestManager的invokingRequest事件。
4. 如果Sys.Net.NetworkRequestEventArgs對(duì)象的cancel屬性為true,取消執(zhí)行Request。
5. 調(diào)用executor對(duì)象的executeRequest方法,以執(zhí)行Request。
三、WebRequestExecutor執(zhí)行Request
在這里,以ASP.NET AJAX的默認(rèn)WebRequestExecutor類:XMLHttpExecutor為例進(jìn)行說明。在XMLHttpExecutor的 executeRequest方法被調(diào)用后,XMLHttpExecutor會(huì)構(gòu)造一個(gè)XMLHttpRequest對(duì)象,并根據(jù)WebRequest的各項(xiàng)屬性設(shè)定XMLHttpRequest的對(duì)象,并指定XMLHttpRequest對(duì)象的onreadystatechange為自身的私有方法 _onReadyStateChange。調(diào)用了executeRequest方法后的關(guān)鍵邏輯如下:
1. 構(gòu)造XMLHttpRequest對(duì)象,并根據(jù)WebRequest對(duì)象的屬性設(shè)定它的各項(xiàng)屬性。
2. 使用window.setTimeout用于監(jiān)聽超時(shí)發(fā)生。
3. 調(diào)用XMLHttpRequest的send方法。
在timeout的響應(yīng)方法中調(diào)用XMLHttpRequest的abort方法,并調(diào)用WebRequest的complete方法。在 _onReadyStateChange方法中清除監(jiān)聽timeout的Timer,并調(diào)用complete方法。當(dāng)然,這只是個(gè)簡(jiǎn)單的描述,事實(shí)上還需要對(duì)Executor的屬性進(jìn)行設(shè)定。我們將在下篇文章中將對(duì)此進(jìn)行詳細(xì)討論。在complete方法被調(diào)用后關(guān)鍵邏輯如下:
1. 觸發(fā)WebRequestManager的completedRequest事件。
2. 觸發(fā)WebRequest的complete事件。
四、用戶響應(yīng)WebRequest的complete事件
在響應(yīng)WebRequest的complete事件時(shí),需要對(duì)于所獲得的結(jié)果進(jìn)行判斷,以確定這個(gè)Request的結(jié)果到底如何,是成功了,還是出錯(cuò)了,亦或是過期了?需要注意的是,我們雖然監(jiān)聽的是WebRequest對(duì)象的事件,但是回調(diào)函數(shù)的***個(gè)參數(shù)是WebRequestExecutor對(duì)象!executor對(duì)象在這里事實(shí)上應(yīng)該被看作是一個(gè)response。我們就來簡(jiǎn)單看一下應(yīng)該如何根據(jù)executor對(duì)象的屬性來判斷 Request的結(jié)果吧。為了對(duì)于這部分邏輯有簡(jiǎn)單而清晰的描述,我就使用代碼片斷來說明吧。代碼框架如下:
- functiononComplete(response,eventArgs){
- if(response.get_aborted()){
- //Abort
- }
- elseif(response.get_responseAvailable()){
- varstatusCode=response.get_statusCode();
- if(((statusCode<200)||(statusCode>=300))){
- //Error
- }
- else{
- //Success
- }
- }
- else{
- if(response.get_timedOut()){
- //Timeout
- }
- else{
- //Error
- }
- }
- }
這就是判斷一個(gè)Request結(jié)果的邏輯框架了,非常清晰。閱讀過ASP.NET AJAX客戶端代碼的朋友們可以發(fā)現(xiàn),在RTM版本中這段邏輯不只一次出現(xiàn)過。我們?nèi)绻枰苯邮褂肳ebRequest對(duì)象時(shí),也應(yīng)該使用這個(gè)邏輯進(jìn)行判斷。
到這里,我們應(yīng)該已經(jīng)搞清楚了從一個(gè)WebRequest對(duì)象被構(gòu)造出來以后,是如何通過WebRequestManager和 WebRequestExecutor而執(zhí)行的,之間會(huì)觸發(fā)哪些事件,而***又是如何通過Response(WebRequestExecutor)對(duì)象來獲得Request的結(jié)果。在下一篇文章中,我們將通過分析WebRequestExecutor、XMLHttpExecutor以及相關(guān)類的實(shí)現(xiàn),來了解應(yīng)該如何自定義和使用一個(gè)WebRequestExecutor。
【編輯推薦】