深入Atlas系列:客户端网络访问基础结构示例(1) - 编写并使用自定义的WebRequestExecutor...
生活随笔
收集整理的這篇文章主要介紹了
深入Atlas系列:客户端网络访问基础结构示例(1) - 编写并使用自定义的WebRequestExecutor...
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
WebRequestExecutor是ASP.NET AJAX網絡訪問基礎結構的唯一修改點。理論上,我們可以使用自定義的WebRequestExecutor來取代默認的XMLHttpExecutor。我們要做的,其實只是開發一個繼承于Sys.Net.WebRequestExecutor類。不過事實上,在實際使用中,Sys.Net.XMLHttpExecutor已經足夠用了,真的要自定義,也只需繼承這個類即可。就像接下去的例子一樣。
可是,Sys.Net.XMLHttpExecutor作為一個父類來說,可以說相當的不友好。先不多說,我們開始吧。在這個例子中,我們將開發一個TraceExecutor,如果使用了這個Executor,Request和Response的信息都會被打印在頁面上,開發人員可以把這些內容作為一個參考。TraceExecutor非常簡單,代碼也很短。
首先,是構造函數代碼。如下:
Jeffz.Net.TraceExecutor?=?function?Jeffz$Net$TraceExecutor()
{
????Jeffz.Net.TraceExecutor.initializeBase(this);
}
一般情況下,在這個方法中,會初始化所有的“私有”變量。不過在這里,我們不需要。
然后,我們將覆蓋XMLHttpExecutor的executeRequest方法,我們需要作的,就是將WebRequest對象打印在頁面上。代碼如下:
function?Jeffz$Net$TraceExecutor$executeRequest()
{
????debug.trace("<b>Request?sent?at?"?+?new?Date()?+?":</b>");
????debug.dump(this.get_webRequest(),?"Request");
????
????Jeffz.Net.TraceExecutor.callBaseMethod(this,?"executeRequest");
}
我在這里使用Debug模式下,為方法起了一個“別名”,在prototype中需要使用一下。自然,我們也需要調用registerClass,表示類的繼承關系。代碼如下:
Jeffz.Net.TraceExecutor.prototype?=?
{
????executeRequest?:?Jeffz$Net$TraceExecutor$executeRequest
}
Jeffz.Net.TraceExecutor.registerClass('Jeffz.Net.TraceExecutor',?Sys.Net.XMLHttpExecutor);
等一下,為什么我們就覆蓋executeRequest這一個方法呢?很顯然,我們只是打印出了Request的信息,那么Response呢?我們是不是還需要再覆蓋另一個方法呢?
我們的確應該再寫一些代碼,用來將Response信息打印出來,但是我們的做法不是覆蓋XMLHttpExecutor的另一個方法,原因有兩點:
因為上面兩個原因(主要是第一個),我們將響應Sys.Net.WebRequestManager.completeRequest事件,在這個事件被觸發時打印Response的信息。代碼如下:
Jeffz.Net.TraceExecutor.traceResponse?=?function?Jeffz$Net$TraceExecutor$traceResponse(response)
{
????debug.trace("<b>Response?received?at?"?+?new?Date()?+?":</b>");
????debug.dump(response,?"Response");
}
Sys.Net.WebRequestManager.add_completedRequest(Jeffz.Net.TraceExecutor.traceResponse);
我們可以嘗試著使用一下,代碼很簡單,將HTML和Javascript一并貼出了。代碼如下:
<asp:ScriptManager?runat="server"?ID="ScriptManager1">
????<Scripts>
????????<asp:ScriptReference?Path="Debug.js"?/>
????????<asp:ScriptReference?Path="TraceExecutor.js"?/>
????</Scripts>
</asp:ScriptManager>
<asp:UpdatePanel?runat="server"?ID="UpdatePanel1">
????<Triggers>
????????<asp:AsyncPostBackTrigger?ControlID="btnRefresh"?/>
????</Triggers>
????<ContentTemplate>
????????<%=?DateTime.Now.ToString("r")?%>
????</ContentTemplate>
</asp:UpdatePanel>
<asp:Button?runat="server"?ID="btnRefresh"?Text="Refresh"/>
<script?language="javascript">
????Sys.Net.WebRequestManager.set_defaultExecutorType("Jeffz.Net.TraceExecutor");
</script>
在這里,需要使用我在《為ASP.NET AJAX 1.0 Beta補充trace和dump功能》里提到的Debug.js來補充ASP.NET AJAX中缺少的trace和dump功能。在代碼的最后會使用Javascript將默認的WebRequestExecutor設為Jeffz.Net.TraceExecutor。
打開頁面,點擊Refresh按鈕,嗯?Request信息不錯,不過Response信息為什么只是這些?
Response?{Jeffz.Net.TraceExecutor}
+_webRequest?{Sys.Net.WebRequest}
+_resultObject:?null
+_xmlHttpRequest?{Object}
+_responseAvailable:?true
+_timedOut:?false
+_timer:?null
+_aborted:?false
+_started:?true
原因在于,由于缺少了了Type Descriptor,debug.dump方法只會將該對象上附屬的“值”(例如:this._started)打印出來,而不會調用任何方法。而在XMLHttpExecutor中,許許多多方法(各種屬性的get方法)是直接將消息委托給XMLHttpRequest對象,而不是將信息保留在XMLHttpExecutor附屬“值”上,因此,我們得到的只能是這些無用的信息了。
那么我們該怎么做?那么就為Response對象補充一個Type Descriptor。這里的Response對象其實就是Jeffz.Net.TraceExecutor類的實例,因此我們需要為該類添加一個Type Descriptor。代碼如下:
Jeffz.Net.TraceExecutor.descriptor?=
{
????properties:
????[
????????{name:?'started',?type:?Boolean?},
????????{name:?'timedOut',?type:?Boolean?},
????????{name:?'aborted',?type:?Boolean?},
????????{name:?'responseAvailable',?type:?Boolean?},
????????{name:?'responseData',?type:?String?},
????????{name:?'statusCode',?type:?Number?},
????????{name:?'statusText',?type:?String?}
????]
}
這是RTM中Type Descriptor的表示方式。可以發現我在這里只添加了部分,而不是全部的屬性。例如缺少了object屬性,為什么呢?在XMLHttpExecutor中get_object方法是這樣定義的:
function?Sys$Net$WebRequestExecutor$get_object()?{
????///?<value></value>
????if?(arguments.length?!==?0)?throw?Error.parameterCount();
????if?(!this._resultObject)?{
????????this._resultObject?=?Sys.Serialization.JavaScriptSerializer.deserialize(this.get_responseData());
????}
????return?this._resultObject;
}
我們可以發現,這段邏輯并沒有判斷responseData的合法性,如果它不是一個正確的JSON字符串,就會拋出異常。如果一定要在Type Descriptor中定義object屬性的話,那么我們還必須在TraceExecutor中覆蓋XMLHttpRequest的object屬性。作為一個沒有多少使用價值的演示,我們就不作得如此“仁至義盡”了。:)
現在我們再來看一下打印出來的內容:
點擊這里下載示例代碼。
可是,Sys.Net.XMLHttpExecutor作為一個父類來說,可以說相當的不友好。先不多說,我們開始吧。在這個例子中,我們將開發一個TraceExecutor,如果使用了這個Executor,Request和Response的信息都會被打印在頁面上,開發人員可以把這些內容作為一個參考。TraceExecutor非常簡單,代碼也很短。
首先,是構造函數代碼。如下:
Jeffz.Net.TraceExecutor?=?function?Jeffz$Net$TraceExecutor()
{
????Jeffz.Net.TraceExecutor.initializeBase(this);
}
一般情況下,在這個方法中,會初始化所有的“私有”變量。不過在這里,我們不需要。
然后,我們將覆蓋XMLHttpExecutor的executeRequest方法,我們需要作的,就是將WebRequest對象打印在頁面上。代碼如下:
function?Jeffz$Net$TraceExecutor$executeRequest()
{
????debug.trace("<b>Request?sent?at?"?+?new?Date()?+?":</b>");
????debug.dump(this.get_webRequest(),?"Request");
????
????Jeffz.Net.TraceExecutor.callBaseMethod(this,?"executeRequest");
}
我在這里使用Debug模式下,為方法起了一個“別名”,在prototype中需要使用一下。自然,我們也需要調用registerClass,表示類的繼承關系。代碼如下:
Jeffz.Net.TraceExecutor.prototype?=?
{
????executeRequest?:?Jeffz$Net$TraceExecutor$executeRequest
}
Jeffz.Net.TraceExecutor.registerClass('Jeffz.Net.TraceExecutor',?Sys.Net.XMLHttpExecutor);
等一下,為什么我們就覆蓋executeRequest這一個方法呢?很顯然,我們只是打印出了Request的信息,那么Response呢?我們是不是還需要再覆蓋另一個方法呢?
我們的確應該再寫一些代碼,用來將Response信息打印出來,但是我們的做法不是覆蓋XMLHttpExecutor的另一個方法,原因有兩點:
- XMLHttpExecute作為一個父類,相當地不友好。可以從代碼里看到,它用來相應XMLHttpRequest對象onreadystatechanged的回調函數“_onReadyStateChanged”是定義在其構造函數內。也就是說,它又使用了Closure,而不是prototype。這樣我們事實上就無法覆蓋那些方法了,如果要繼續在TraceExecutor上面做文章的話,我們必須寫大量的代碼,這幾乎就相當于重新寫了一個WebRequestExecutor。為什么會出現這種情況?是XMLHttpExecutor故意寫成這個樣的嗎?我們來看一下:在XMLHttpRequest代碼的executeRequest方法中,設置XMLHttpRequest對象onreadystatechanged的代碼是:“this._xmlHttpRequest.onreadystatechanged = this._onReadyStateChanged”,然后在_onReayStateChanged方法中使用了保留在Closure之中的“_this”變量。這個是沒有“Function.createDelegate”時,或者在使用Closure時的寫法,編寫過Windows Live Gadget的朋友們可以回憶一下,在使用官方提供的模版時,是不是在一開始也保留了一個“m_this”變量?這是相似的原因。那么在XMLHttpExecutor里,為什么不使用“Function.createDelegate”方法?估計只有負責這部分代碼的開發人員才知道了。因此,我認為這里部分使用了Closure不是故意所為,這更像是負責這段代碼的開發人員一時“神志錯亂”。
- 即使我們覆蓋了“_onReadyStateChanged”方法,我們還漏了一些別的。如果這個Request超時了呢?如果這個Request被abort了呢?如果我們一一覆蓋這些方法的話,似乎也有些太麻煩了。
因為上面兩個原因(主要是第一個),我們將響應Sys.Net.WebRequestManager.completeRequest事件,在這個事件被觸發時打印Response的信息。代碼如下:
Jeffz.Net.TraceExecutor.traceResponse?=?function?Jeffz$Net$TraceExecutor$traceResponse(response)
{
????debug.trace("<b>Response?received?at?"?+?new?Date()?+?":</b>");
????debug.dump(response,?"Response");
}
Sys.Net.WebRequestManager.add_completedRequest(Jeffz.Net.TraceExecutor.traceResponse);
我們可以嘗試著使用一下,代碼很簡單,將HTML和Javascript一并貼出了。代碼如下:
<asp:ScriptManager?runat="server"?ID="ScriptManager1">
????<Scripts>
????????<asp:ScriptReference?Path="Debug.js"?/>
????????<asp:ScriptReference?Path="TraceExecutor.js"?/>
????</Scripts>
</asp:ScriptManager>
<asp:UpdatePanel?runat="server"?ID="UpdatePanel1">
????<Triggers>
????????<asp:AsyncPostBackTrigger?ControlID="btnRefresh"?/>
????</Triggers>
????<ContentTemplate>
????????<%=?DateTime.Now.ToString("r")?%>
????</ContentTemplate>
</asp:UpdatePanel>
<asp:Button?runat="server"?ID="btnRefresh"?Text="Refresh"/>
<script?language="javascript">
????Sys.Net.WebRequestManager.set_defaultExecutorType("Jeffz.Net.TraceExecutor");
</script>
在這里,需要使用我在《為ASP.NET AJAX 1.0 Beta補充trace和dump功能》里提到的Debug.js來補充ASP.NET AJAX中缺少的trace和dump功能。在代碼的最后會使用Javascript將默認的WebRequestExecutor設為Jeffz.Net.TraceExecutor。
打開頁面,點擊Refresh按鈕,嗯?Request信息不錯,不過Response信息為什么只是這些?
Response?{Jeffz.Net.TraceExecutor}
+_webRequest?{Sys.Net.WebRequest}
+_resultObject:?null
+_xmlHttpRequest?{Object}
+_responseAvailable:?true
+_timedOut:?false
+_timer:?null
+_aborted:?false
+_started:?true
原因在于,由于缺少了了Type Descriptor,debug.dump方法只會將該對象上附屬的“值”(例如:this._started)打印出來,而不會調用任何方法。而在XMLHttpExecutor中,許許多多方法(各種屬性的get方法)是直接將消息委托給XMLHttpRequest對象,而不是將信息保留在XMLHttpExecutor附屬“值”上,因此,我們得到的只能是這些無用的信息了。
那么我們該怎么做?那么就為Response對象補充一個Type Descriptor。這里的Response對象其實就是Jeffz.Net.TraceExecutor類的實例,因此我們需要為該類添加一個Type Descriptor。代碼如下:
Jeffz.Net.TraceExecutor.descriptor?=
{
????properties:
????[
????????{name:?'started',?type:?Boolean?},
????????{name:?'timedOut',?type:?Boolean?},
????????{name:?'aborted',?type:?Boolean?},
????????{name:?'responseAvailable',?type:?Boolean?},
????????{name:?'responseData',?type:?String?},
????????{name:?'statusCode',?type:?Number?},
????????{name:?'statusText',?type:?String?}
????]
}
這是RTM中Type Descriptor的表示方式。可以發現我在這里只添加了部分,而不是全部的屬性。例如缺少了object屬性,為什么呢?在XMLHttpExecutor中get_object方法是這樣定義的:
function?Sys$Net$WebRequestExecutor$get_object()?{
????///?<value></value>
????if?(arguments.length?!==?0)?throw?Error.parameterCount();
????if?(!this._resultObject)?{
????????this._resultObject?=?Sys.Serialization.JavaScriptSerializer.deserialize(this.get_responseData());
????}
????return?this._resultObject;
}
我們可以發現,這段邏輯并沒有判斷responseData的合法性,如果它不是一個正確的JSON字符串,就會拋出異常。如果一定要在Type Descriptor中定義object屬性的話,那么我們還必須在TraceExecutor中覆蓋XMLHttpRequest的object屬性。作為一個沒有多少使用價值的演示,我們就不作得如此“仁至義盡”了。:)
現在我們再來看一下打印出來的內容:
點擊這里下載示例代碼。
轉載于:https://www.cnblogs.com/JeffreyZhao/archive/2006/10/30/Inside_Atlas_Series__Client_Communication_Architecture__Sample_1.html
總結
以上是生活随笔為你收集整理的深入Atlas系列:客户端网络访问基础结构示例(1) - 编写并使用自定义的WebRequestExecutor...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VC#打包部署全攻略之(一、添加卸载程序
- 下一篇: XP 风格的可拖动列、可排序、可改变宽度