ASP.NET AJAX(8)__Microsoft AJAX Library中非同步通訊層的使用什麼是非同步通訊層Micorsoft AJAX Library非同步通訊層的組成WebRequestExec
阿新 • • 發佈:2022-05-03
什麼是非同步通訊層
- Microsoft AJAX Library的組長部分之一
- 負責ASP.NET AJAX框架中所有的客戶端與伺服器端的通訊
- 其預設實現了封裝了XMLHttpRequest的功能
一個使用XMLHttpRequest發出AJAX請求的示例
建立一個名為RandomNumber.ashx的一般處理程式
<%@ WebHandler Language="C#" Class="RandomNumber" %> using System; using System.Web; public class RandomNumber : IHttpHandler { private static Random random = new Random(DateTime.Now.Millisecond); public void ProcessRequest (HttpContext context) { context.Response.ContentType = "text/plain"; context.Response.Write(random.Next()); } public bool IsReusable { get { return false; } } }
建立一個htm頁面
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script language="javascript" type="text/javascript"> function getXMLHttpRequest() {//獲得XMLHttpRequest物件 if (window.XMLHttpRequest) {//如果有原生的XMLHttpRequest,IE6+、firefox都有 return new window.XMLHttpRequest(); } else {//如果沒有原生的XMLHttpRequest var progIDs = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP']; for (var i = 0; i < progIDs.length; i++) { try { var xmlHttp = new ActiveXObject(progIDs[i]); return xmlHttp; } catch (ex) { } } return null; } } function sendRequest() { var xhr = getXMLHttpRequest(); //第一個引數:傳送請求的方式。第二個引數:請求發給的地址。第三個引數:true非同步更新(預設),false阻塞更新 xhr.open("POST", "RandomNumber.ashx", true); xhr.onreadystatechange = function() {//指定回撥函式 onReadyStateChange.apply(xhr);//將xhr作為this指標 } xhr.send(null);//傳送請求,引數為請求的body } function onReadyStateChange() { if (this.readyState == 4) {//readyState==4表示得到結果 if (this.status == 200) {//status==200表示得到結果正常 alert(this.responseText); } } else { } } </script> </head> <body> <input type="button" value="Send" onclick="sendRequest()" /> </body> </html>
註釋中我已經寫的很清楚,XMLHttpRequest在當他的readyState改變以後,呼叫我們定義的onReadyStateChange,然後通過判斷一些狀態來驗證是否得到了我們想要資料,而不是伺服器端丟擲的錯誤等等
Micorsoft AJAX Library非同步通訊層的組成
- 均在Sys.Net名稱空間下
- WebRequest類:負責手機儲存請求資訊
- WebRequestExecutor類:負責傳送請求,反饋伺服器端回覆的結果
- WebRequestManager類:使用者管理非同步通訊層與伺服器端的通訊 WebRequest類成員
- completed事件:得到回覆後出發
- completed方法:引發completed事件
- getResolvedUrl方法:獲得完整的URL
- invoke方法:傳送請求
- body屬性:傳送到伺服器的內容
- executor屬性:傳送請求的Executor物件
- headers屬性:請求的頭資訊集合
- httpVerb屬性:請求使用的HTTP方法
- timtout屬性:超時時間
- url屬性:請求的URL
- userContext屬性:附加於WebRequest的物件
WebRequestExexutor成員
- abort方法:取消當前請求
- executorRequest方法:執行請求
- getAllResponseHeaders方法:獲取回覆內所有的標頭檔案
- getResponseHeader方法:獲得回覆指定的頭資訊
- aborted屬性:表示請求是否被取消
- responseAvailable屬性:表示是否得到了正確的結果
- responseData屬性:獲得字串形式的回覆內容
- started屬性:表示請求是否已經開始
- statusCode屬性:表示回覆狀態的程式碼
- statusText屬性:表示回覆狀態的文字
- timedOut屬性:表示是否超時
- xml屬性:獲得xml形式的回覆內容
- webRequest屬性:獲得當前正在執行的WebRequest物件
使用非同步通訊層的示例
首先建立一個名為Complex.ashx的一般處理程式
<%@ WebHandler Language="C#" Class="Complex" %>
using System;
using System.Web;
public class Complex : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
string action = context.Request.Headers["action"];//得到Header中key為action的值
if (action == "normal")
{
context.Response.Write("You've sent:" + context.Request.Params["data"]);//把傳過來的data值做處理,然後寫回
}
else if (action == "error")
{
throw new Exception();//丟擲一個異常
}
else
{
System.Threading.Thread.Sleep(5000);//執行緒停止5秒,如果客戶端設定超時小於五秒,則會造成一個超時錯誤
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
然後建立一個aspx頁面
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script language="javascript" type="text/javascript">
var webRequest=null;
function sendRequest(action) {
webRequest = new Sys.Net.WebRequest();
webRequest.set_url("Complex.ashx");//設定請求路徑
webRequest.get_headers()["action"] = action;//設定一個key為action的Header
webRequest.set_body("data=" + encodeURIComponent("Xiaoyaojian"));//設定傳送的內容
webRequest.set_httpVerb("POST");//設定請求使用的HTTP方法
webRequest.set_timeout(3000);//設定超時時間
webRequest.add_completed(onCompleted);//新增完成時候的回撥函式
webRequest.invoke();//執行請求
}
function onCompleted(response, eventArgs) {
if (response.get_aborted()) {//判斷是否被取消
alert("Request aborted!");
}
else if (response.get_responseAvailable()) {//判斷得到的資訊是否正確
var statusCode = response.get_statusCode();//得到狀態碼
if (statusCode < 200 || statusCode >= 300) {//狀態碼小於200或者大於等於300,則表示出現了錯誤
alert("Error occurred!");
}
else {
alert(response.get_responseData());//回覆的資訊
}
}
else {
if (response.get_timedOut()) {//判斷是否為超時
alert("Request timed out!");
}
else {
alert("Error occurred!");
}
}
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<input type="button" value="Normal" onclick="sendRequest('normal');" />
<input type="button" value="Error" onclick="sendRequest('error');" />
<input type="button" value="Time out" onclick="sendRequest('ad');" />
<input type="button" value="Abort" onclick="webRequest.get_executor().abort()" />
</form>
</body>
</html>
點選Normal,得到正常的結果,點選Error,出現一個錯誤,點選Time out,得到一個超時錯誤,點選Abort,可以取消一個請求,我們可以使用先點選Time out,然後在三秒內點選Abort來得到一個取消的效果
WebRequestManager成員
- invokingRequest事件:即將傳送請求時候觸發,可用於取消某個請求
- completedRequest事件:請求結束時候觸發,他早於WebRequest物件的completed事件
- defaultTimeout屬性:預設超時時間
- defaultExecutorType屬性:預設的傳送請求的Executor型別
使用WebRequestManager的事件的示例
建立一個aspx頁面
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<%= DateTime.Now %><hr />
<asp:Button ID="Button1" runat="server" Text="Button" />
</ContentTemplate>
</asp:UpdatePanel>
<script language="javascript" type="text/javascript">
Sys.Net.WebRequestManager.add_invokingRequest(function(sender, eventArgs) {
if (confirm("Concel the partial rendering?")) {//在即將發起請求的時候,引數提示,讓使用者確認
eventArgs.set_cancel(true);//取消操作
}
});
Sys.Net.WebRequestManager.add_completedRequest(function() {//在請求結束以後,WebRequest的completed沒有被觸發之前,給出一個提示
alert("Response received!");
});
</script>
</form>
</body>
</html>
示例簡單的。。。我都不知道該說什麼了,就是響應了WebRequestManager的兩個事件。。。。。。
WebRequestExecutor類成員
- abort方法:取消當前操作
- executeRequest方法:執行請求
- getAllResponseHeaders方法:獲取回覆中所有的頭資訊
- getResponseHeader方法:獲取回覆中指定KEY的頭資訊
- aborted屬性:表示請求是否被取消
- responseAvailable屬性:表示是否得到了正確的結果
- responseData屬性:獲得字串形式的回覆內容
- started屬性:表示請求是否已經開始
- statusCode屬性:表示回覆狀態程式碼
- statusText屬性:表示回覆狀態的問題
- timedOut屬性:表示回覆是否為超時
- xml屬性:獲得xml形式的回覆內容
- webRequest屬性:獲得當前正在執行的WebRequest物件
實現ScriptReferenceExecutor
- 實現簡單屬性(aborted,responseAvailable,responseData,started,statusCode,statusText,timedOut,xml)
- 實現executeRequest方法(傳送資訊,監聽超時)
- 實現完成、超時、取消邏輯
- 清楚超時監聽和其他一些輔助物件
- 呼叫WebRequest的completed方法
- 實現不支援的方法:getAllResponseHeaders方法,getResponseHeader方法
一個實現executeRequest方法的示例
首先建立一個名為ScriptRerenceExcutor.js的js檔案
Sys.Net.ScriptReferenceExecutor = function() {//建構函式
Sys.Net.ScriptReferenceExecutor.initializeBase(this);//呼叫基類的建構函式
//初始化一些私有的變數
this._responseAvailable = false;
this._timedOut = false;
this._aborted = false;
this._started = false;
this._responseData = null;
this._statusCode = 0;
this._statusText = null;
this._uniqueKey = null;
this._timer = null;
this._scriptElement = null;
}
Sys.Net.ScriptReferenceExecutor.prototype =
{
//定義一些簡單屬性
get_responseAvailable: function() {
return this._responseAvailable;
},
get_timedOut: function() {
return this._timedOut;
},
get_aborted: function() {
return this._aborted;
},
get_started: function() {
return this._started;
},
get_responseData: function() {
return this._responseData;
},
get_statusCode: function() {
return this._statusCode;
},
get_statusText: function() {
return this._statusText;
},
//把get_responseData()得到的結果,然後進行XML轉換
get_xml: function() {
return new XMLDOM(this.get_responseData());
},
executeRequest: function() {
this._started = true;//表示執行已經開始
var request = this.get_webRequest();//得到webRequest物件的資訊
var serializer = Sys.Serialization.JavaScriptSerializer;//Microsoft AJAX Library提供給我們進行JSON序列化和反序列化的方法
//以下是拼接QueryString的過程
var scriptUrl = request.get_url() + "?";
scriptUrl += (("headers=") + encodeURIComponent(serializer.serialize(request.get_headers())));
scriptUrl += ("&body=" + encodeURIComponent(serializer.serialize(request.get_body())));
var uniqueKey = this._uniqueKey = this._generateUniqueKey();//此欄位確定載入的SciptRequestExecutor是由誰發起的
scriptUrl += ("&uniqueKey=" + encodeURIComponent(serializer.serialize(uniqueKey)));
Sys.Net.ScriptReferenceExecutor._executors[uniqueKey] = this; //把字的uniqueKey儲存起來
var scriptElement = this._scriptElement = document.createElement("script");
scriptElement.type = "text/javascript";
scriptElement.language = "javascript";
scriptElement.src = scriptUrl;
document.getElementsByTagName("head")[0].appendChild(scriptElement);
//設定超時
var timeout = request.get_timeout();
if (timeout > 0) {
this._timer = window.setTimeout(
Function.createDelegate(this, this._onTimeout), timeout);
}
},
_onTimeout: function() {//設定超時執行的操作
this.complete(null, null, null, false, true, false);
},
abort: function() {//設定取消操作後執行的操作
this.complete(null, null, null, false, false, true);
},
_generateUniqueKey: function() {
return Math.random().toString();//通常已經足夠使用,當然還是可以採用其他一些更嚴格的做法
},
complete: function(statusCode, statusText, body, responseAvailable, timedOut, aborted) {
this._statusCode = statusCode;
this._statusText = statusText;
this._responseData = body;
this._responseAvailable = responseAvailable;
this._timedOut = timedOut;
this._aborted = aborted;
if (this._timer) {
window.clearTimeout(this._timer);
}
document.getElementsByTagName("head")[0].removeChild(this._scriptElement);
delete Sys.Net.ScriptReferenceExecutor._executors[this._uniqueKey];
this.get_webRequest().completed(Sys.EventArgs.Empty);
}
}
Sys.Net.ScriptReferenceExecutor.registerClass("Sys.Net.ScriptReferenceExecutor", Sys.Net.WebRequestExecutor);
Sys.Net.ScriptReferenceExecutor._executors = new Object();
Sys.Net.ScriptReferenceExecutor.complete = function(uniqueKey, statusCode, statusText, body) {
var executor = Sys.Net.ScriptReferenceExecutor._executors[uniqueKey];
if (executor) {
executor.complete(statusCode, statusText, body, true, false, false);
}
}
然後建立一個名為ScriptReferenceExecutor.ashx的一般處理程式
<%@ WebHandler Language="C#" Class="ScriptReferenceExecutor" %>
using System;
using System.Web;
using System.Web.Script.Serialization;
using System.Collections.Generic;
public class ScriptReferenceExecutor : IHttpHandler
{
public void ProcessRequest (HttpContext context)
{
context.Response.ContentType = "text/plain";
JavaScriptSerializer serializer = new JavaScriptSerializer();
Dictionary<string, string> headers = serializer.Deserialize<Dictionary<string, string>>(context.Request.QueryString["headers"]);
string body = serializer.Deserialize<string>(context.Request.QueryString["body"]);
string uniqueKey = serializer.Deserialize<string>(context.Request.QueryString["uniqueKey"]);
string action = headers["action"];
if (action == "normal")
{
this.SendResponse(context, uniqueKey, 200, "OK", "You've send: " + body);
}
else if (action == "error")
{
this.SendResponse(context, uniqueKey, 500, "Error", null);
}
else
{
System.Threading.Thread.Sleep(5000);
}
}
private void SendResponse(HttpContext context, string uniqueKey, int statusCode, string statusText, string body)
{
context.Response.Write("Sys.Net.ScriptReferenceExecutor.complete('" + uniqueKey + "', ");
context.Response.Write("'" + statusCode + "', ");
context.Response.Write("'" + statusText + "', ");
context.Response.Write(new JavaScriptSerializer().Serialize(body) + ");");
}
public bool IsReusable
{
get
{
return false;
}
}
}
然後建立一個aspx頁面,引入我們建立的js檔案
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script language="javascript" type="text/javascript">
var webRequest=null;
function sendRequest(action) {
webRequest = new Sys.Net.WebRequest();
webRequest.set_url("ScriptReferenceExecutor.ashx"); //設定請求路徑
webRequest.get_headers()["action"] = action;//設定一個key為action的Header
webRequest.set_body("data=" + encodeURIComponent("Xiaoyaojian"));//設定傳送的內容
webRequest.set_httpVerb("POST");//設定請求使用的HTTP方法
webRequest.set_timeout(3000);//設定超時時間
webRequest.set_executor(new Sys.Net.ScriptReferenceExecutor());
webRequest.add_completed(onCompleted);//新增完成時候的回撥函式
webRequest.invoke();//執行請求
}
function onCompleted(response, eventArgs) {
if (response.get_aborted()) {//判斷是否被取消
alert("Request aborted!");
}
else if (response.get_responseAvailable()) {//判斷得到的資訊是否正確
var statusCode = response.get_statusCode();//得到狀態碼
if (statusCode < 200 || statusCode >= 300) {//狀態碼小於200或者大於等於300,則表示出現了錯誤
alert("Error occurred!");
}
else {
alert(response.get_responseData());//回覆的資訊
}
}
else {
if (response.get_timedOut()) {//判斷是否為超時
alert("Request timed out!");
}
else {
alert("Error occurred!");
}
}
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Path="~/Demo07/ScriptRerenceExcutor.js" />
</Scripts>
</asp:ScriptManager>
<input type="button" value="Normal" onclick="sendRequest('normal');" />
<input type="button" value="Error" onclick="sendRequest('error');" />
<input type="button" value="Time out" onclick="sendRequest('ad');" />
<input type="button" value="Abort" onclick="webRequest.get_executor().abort()" />
</form>
</body>
</html>
這樣。我們就成功的使用了自定義的Executor