调用Page.RegisterAsyncTask()的异步页

我一直认为ASP.NET程序也是一种服务程序,它要对客户端浏览器发出的请求而服务。 由于是服务,对于要服务的对象来说,都希望能尽快地得到响应,这其实也是对服务的一个基本的要求, 那就是:高吞量地快速响应。

对于前面所说的方法,显然,它的所有异步任务都是串行执行的,对于客户端来说,等待的时间会较长。 而且,最严重的是,如果服务超时,上面的方法会一直等待,直到本次请求超时。 为了解决这二个问题,ASP.NET定义了一种异步任务类型:PageAsyncTask 。它可以解决以上二种问题。 首先我们还是来看一下PageAsyncTask类的定义:(说明:这个类的关键就是它的构造函数)

复制代码
// 摘要:
//     使用并行执行的指定值初始化 System.Web.UI.PageAsyncTask 类的新实例。
//
// 参数:
//   state:
//     表示任务状态的对象。
//
//   executeInParallel:
//     指示任务能否与其他任务并行处理的值。
//
//   endHandler:
//     当任务在超时期内成功完成时要调用的处理程序。
//
//   timeoutHandler:
//     当任务未在超时期内成功完成时要调用的处理程序。
//
//   beginHandler:
//     当异步任务开始时要调用的处理程序。
//
// 异常:
//   System.ArgumentNullException:
//     beginHandler 参数或 endHandler 参数未指定。
public PageAsyncTask(BeginEventHandler beginHandler, EndEventHandler endHandler, 
			EndEventHandler timeoutHandler, object state, bool executeInParallel);

注意这个构造函数的签名,它与AddOnPreRenderCompleteAsync()相比,多了二个参数:EndEventHandler timeoutHandler, bool executeInParallel 。 它们的含义上面的注释中有说明,这里只是提示您要注意它们而已。

创建好一个PageAsyncTask对象后,只要调用页面的RegisterAsyncTask()方法就可以注册一个异步任务。 具体用法可参考我的如下代码:(注意代码中的注释)

复制代码
protected void button1_click(object sender, EventArgs e)
{
    Trace.Write("button1_click ThreadId = " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());

    // 准备回调数据,它将由PageAsyncTask构造函数的第四个参数被传入。
    MyHttpClient<string, string> http = new MyHttpClient<string, string>();
    http.UserData = textbox1.Text;

    // 创建异步任务
    PageAsyncTask task = new PageAsyncTask(BeginCall, EndCall, TimeoutCall, http);
    // 注册异步任务
    RegisterAsyncTask(task);
}

private IAsyncResult BeginCall(object sender, EventArgs e, AsyncCallback cb, object extraData)
{
    // 在这个方法中,
    // sender 就是 this
    // e 就是 EventArgs.Empty
    // cb 是ASP.NET定义的一个委托,我们只管在异步调用它时把它用作回调委托就行了。
    // extraData 就是PageAsyncTask构造函数的第四个参数
    Trace.Warn("BeginCall ThreadId = " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());

    MyHttpClient<string, string> http = (MyHttpClient<string, string>)extraData;

    // 开始一个异步调用。
    return http.BeginSendHttpRequest(ServiceUrl, (string)http.UserData, cb, http);
}

private void EndCall(IAsyncResult ar)
{
    // 到这个方法中,表示一个任务执行完毕。
    // 参数 ar 就是BeginCall的返回值。
    Trace.Warn("EndCall ThreadId = " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());

    MyHttpClient<string, string> http = (MyHttpClient<string, string>)ar.AsyncState;
    string str = (string)http.UserData;

    try {
        // 结束异步调用,获取调用结果。如果有异常,也会在这里抛出。
        string result = http.EndSendHttpRequest(ar);
        labMessage.Text = string.Format("{0} => {1}", str, result);
    }
    catch( Exception ex ) {
        labMessage.Text = string.Format("{0} => Error: {1}", str, ex.Message);
    }
}

private void TimeoutCall(IAsyncResult ar)
{
    // 到这个方法,就表示任务执行超时了。
    Trace.Warn("TimeoutCall ThreadId = " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());

    MyHttpClient<string, string> http = (MyHttpClient<string, string>)ar.AsyncState;
    string str = (string)http.UserData;

    labMessage.Text = string.Format("{0} => Timeout.", str);
}

前面我说过PageAsyncTask是支持超时的,那么它的超时功能是如何使用的呢,上面的示例只是给了一个超时的回调委托而已。

在开始演示PageAsyncTask的高级功能前,有必要说明一下示例所调用的服务端代码。 本示例所调用的服务是【C#客户端的异步操作】中使用的演示服务, 服务代码如下:

复制代码
[MyServiceMethod]
public static string ExtractNumber(string str)
{
    // 延迟3秒,模拟一个长时间的调用操作,便于客户演示异步的效果。
    System.Threading.Thread.Sleep(3000);

    if( string.IsNullOrEmpty(str) )
        return "str IsNullOrEmpty.";

    return new string((from c in str where Char.IsDigit(c) orderby c select c).ToArray());
}

下面的示例我将演示开始二个异步任务,并设置异步页的超时时间为4秒钟。

复制代码
protected void button1_click(object sender, EventArgs e)
{
    Trace.Write("button1_click ThreadId = " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());

    // 设置页面超时时间为4秒
    Page.AsyncTimeout = new TimeSpan(0, 0, 4);

    // 注册第一个异步任务
    MyHttpClient<string, string> http = new MyHttpClient<string, string>();
    http.UserData = textbox1.Text;
    PageAsyncTask task = new PageAsyncTask(BeginCall, EndCall, TimeoutCall, http);
    RegisterAsyncTask(task);

    // 注册第二个异步任务
    MyHttpClient<string, string> http2 = new MyHttpClient<string, string>();
    http2.UserData = "T2_" + Guid.NewGuid().ToString();
    PageAsyncTask task2 = new PageAsyncTask(BeginCall2, EndCall2, TimeoutCall2, http2);
    RegisterAsyncTask(task2);
}

此页面的执行过程如下:

确实,第二个任务执行超时了。

再来看一下PageAsyncTask所支持的任务的并行执行是如何调用的:

复制代码
protected void button1_click(object sender, EventArgs e)
{
    Trace.Write("button1_click ThreadId = " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());

    // 设置页面超时时间为4秒
    Page.AsyncTimeout = new TimeSpan(0, 0, 4);

    // 注册第一个异步任务
    MyHttpClient<string, string> http = new MyHttpClient<string, string>();
    http.UserData = textbox1.Text;
    PageAsyncTask task = new PageAsyncTask(BeginCall, EndCall, TimeoutCall, http, true /*注意这个参数*/);
    RegisterAsyncTask(task);

    // 注册第二个异步任务
    MyHttpClient<string, string> http2 = new MyHttpClient<string, string>();
    http2.UserData = "T2_" + Guid.NewGuid().ToString();
    PageAsyncTask task2 = new PageAsyncTask(BeginCall2, EndCall2, TimeoutCall2, http2, true /*注意这个参数*/);
    RegisterAsyncTask(task2);
}

此页面的执行过程如下:

图片清楚地反映出,这二个任务是并行执行时,所以,这二个任务能在4秒内同时执行完毕。

在结束对PageAsyncTask的介绍前,有必要对超时做个说明。 对于使用PageAsyncTask的异步页来说,有二种方法来设置超时时间:

  1. 通过Page指令: asyncTimeout="0:00:45" ,这个值就是异步页的默认值。至于这个值的含义,我想您应该懂的。

  2. 通过设置 Page.AsyncTimeout = new TimeSpan(0, 0, 4); 这种方式。示例代码就是这种方式。

注意:由于AsyncTimeout是Page级别的参数,因此,它是针对所有的PageAsyncTask来限定的,并非每个PageAsyncTask的超时都是这个值。

相关推荐
2501_915106323 小时前
第一次开发 iPhone App,可能碰到的问题,解决办法
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
2501_915106323 小时前
iOS数据采集技术详解:从性能监控到崩溃分析的全链路实践
android·ios·小程序·https·uni-app·iphone·webview
末代iOS程序员华仔19 小时前
iOS 5.6 条例解决方法
flutter·ios·swift
末代iOS程序员华仔1 天前
Guideline 5.6 - Developer Code of Conduct
flutter·ios·swift
2501_915918411 天前
Flutter项目配置iOS混淆的详细步骤与工具推荐
android·flutter·ios·小程序·uni-app·cocoa·iphone
凡泰AI1 天前
如何通过小程序多端框架,让一个小程序同时运行在iOS、安卓、鸿蒙和微信客户端,实现开发层面的降本增效
android·ios·微信小程序·小程序·harmonyos
2501_915106322 天前
安卓抓包软件2026,免证书抓包 应用层抓包 代理抓包全解析
网络协议·计算机网络·网络安全·ios·adb·https·udp
kango2 天前
Xcode、模拟器Runtime、真机符号完整知识手册
ios·app
用户38034165882972 天前
50MB 红线下的 iOS 录屏引擎:ReplayKit Broadcast Extension 实战
ios
Privasa-隐私实验室2 天前
跨端技术选型|Flutter搭建隐私加密App,安卓与iOS双端差异适配实战
android·笔记·安全·flutter·ios·隐私安全·aes-256