ASP.NET AJAX(8)__Microsoft AJAX Library中异步通信层的使用什么是异步通信层Micorsoft AJAX Library异步通信层的组成WebRequestExec

什么是异步通信层

  • 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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏BY的专栏

Swift 3.1的新改动

3555
来自专栏菩提树下的杨过

java: web应用中不经意的内存泄露

前面有一篇讲解如何在spring mvc web应用中一启动就执行某些逻辑,今天无意发现如果使用不当,很容易引起内存泄露,测试代码如下: 1、定义一个类App ...

2165
来自专栏一名叫大蕉的程序员

简易但不简单的配置中心No.79

嘛小伙伴们都问我我是怎么抽那么多时间来看书的,其实说难也不难说简单其实也不简单,就是提高效率和挤时间嘛。你要相信在一天中,每个时间都有它自己应该待的位置,做好工...

1949
来自专栏木宛城主

迁移TFS,批量将文档导入SharePoint 2013 文档库

一、需求分析 公司需要将存在于旧系统(TFS)所有的文档迁移至新系统(SharePoint 2013)。现已经将50G以上的文档拷贝到SharePoint ...

18110
来自专栏游戏开发那些事

【Unity游戏开发】用C#和Lua实现Unity中的事件分发机制EventDispatcher

  最近马三换了一家大公司工作,公司制度规范了一些,因此平时的业余时间多了不少。但是人却懒了下来,最近这一个月都没怎么研究新技术,博客写得也是拖拖拉拉,周六周天...

794
来自专栏张善友的专栏

自动类型安全的.NET标准REST库refit

在SCOTT HANSELMAN 博客上看到一个好东西《Exploring refit, an automatic type-safe REST library...

1777
来自专栏大内老A

[ASP.NET MVC] 利用自定义的AuthenticationFilter实现Basic认证

很多情况下目标Action方法都要求在一个安全上下文中被执行,这里所谓的安全上下文主要指的是当前请求者是一个经过授权的用户。授权的本质就是让用户在他许可的权限范...

20210
来自专栏aoho求索

Spring Cloud 覆写远端的配置属性

覆写远端的配置属性 应用的配置源通常都是远端的Config Server服务器,默认情况下,本地的配置优先级低于远端配置仓库。如果想实现本地应用的系统变量和c...

3539
来自专栏飞雪无情的博客

Go语言经典库使用分析(六)| Negroni 中间件(二)

上一篇 Go语言经典库使用分析(五)| Negroni 中间件(一) 中介绍了Negroni中间的入门使用和一些介绍,比如如何添加中间等,中间件的路由等。这一篇...

683
来自专栏熊二哥

快速入门系列--WebAPI--04在老版本MVC4下的调整

WebAPI是建立在MVC和WCF的基础上的,原来微软老是喜欢封装的很多,这次终于愿意将http编程模型的相关细节暴露给我们了。在之前的介绍中,基本上都基于.N...

1966

扫描关注云+社区