IAsyncResult

在第 1 部分和第 2 部分中,
建立了 WeatherDataSource 控件,该控件针对 weather.com(英文)所提供的 XML API 来运行,使用 WebRequest 和 WebResponse 来通过 HTTP 访问数据。迄今为止,均是同步访问该服务。因此,页面处理被阻止,直到 Web 请求完成为止。此方法对于测试页面是有效的,在小站点上也可能有效,但是在接收大量通信流量的站点上则会惨败;例如门户页面,天气模块在其中可能非常常见。

  引言

  在线程池中有固定不变的大量线程可用于服务请求,遗憾的是,该解决方案并非仅仅提高限制(还会增加线程占用资源以及 CPU 占用资源)。因此,当一个页面被阻止而等候另一个服务器时,它还在占用线程,因而可能会导致其他传入的请求在队列中等候更长的时间。这将导致对站点的访问变慢,并降低 CPU 的利用率。在 Visual Studio 2005 中,我们引入了异步页面,这使得控件能够定义它们希望异步完成的任务,即,无需阻止用来处理请求的线程。在此将不介绍异步页面本身的详细信息,Dmitry(英文)和 Fritz Onion(英文)中以前已经有所介绍。此处要介绍的是如何在数据源控件中利用此功能,使用加载项框架来实现异步数据源。

  背景

  在第 1 部分中,间接提到了 DataSourceView 类的有些古怪的设计:

public abstract class DataSourceView {
 public virtual void Select(DataSourceSelectArguments arguments,
  DataSourceViewSelectCallback callback);
 protected abstract IEnumerable ExecuteSelect(
  DataSourceSelectArguments arguments);
 ...
}

  您会注意到,公共 Select 方法实际上并不返回任何数据。而是接受一个回拨,并通过该回拨来返回数据。它只调用受保护的 ExecuteSelect(它始终执行同步数据访问)来检索要退还给数据绑定控件的数据。DataSourceView 类的默认实现实际上不会异步执行任何操作。原因在于,并不存在任何现成的异步数据源控件。但 OM 的设计确实允许实现异步数据访问,在这种设计下,数据在异步工作完成之后才可用。因此,我们就有了一个基于回拨的模型。

  那些熟悉框架中的异步 API 的人会注意到缺少了异步模式:公共 Select、BeginSelect 和 EndSelect 方法,在这些方法中,数据绑定控件选择要调用哪些方法。但是,数据绑定控件并不能确定是选择同步 API 还是选择异步 API。此外,在数据绑定控件上添加属性也毫无作用。数据源控件封装了有关如何访问数据存储的详细信息,对数据存储的访问是同步发生还是异步发生应该根据数据源是否基于语义来决定或者根据自定义属性来决定。潜在的“bool PerformAsyncDataAccess”属性的正确位置适合于数据源控件本身。这还使得数据源控件可以使用一种方法来执行数据访问,即使多个数据绑定控件被绑定到同一个数据源。至此已多次解释了该体系结构所蕴涵的这些微妙的概念,但愿能阐明该设计。

  关于异步任务,最后要注意的一点是:页面是否应该执行任何异步工作完全由页面开发人员最终决定(通过 Page 指令的 Async 属性)。因此,任何编写良好的数据源控件必须退化为根据需要来执行同步数据访问。

  框架

  在此框架中(在此系列结尾会用示例的剩余部分来演示这一点),已将 AsyncDataSource 和 AsyncDataSourceView 基类放在一起,这些基类可以用于实现能够执行异步数据访问的数据源控件。以下大概介绍了框架内容,以及有助于弄清楚其含义的一些注释:

public abstract class AsyncDataSourceControl : DataSourceControl,
IAsyncDataSource {
private bool _performAsyncDataAccess;

protected AsyncDataSourceControl() {
 _performAsyncDataAccess = true;
}

public virtual bool PerformAsyncDataAccess {
 get; set;
}

bool IAsyncDataSource.IsAsync {
 get { return _performAsyncDataAccess && Page.IsAsync; }
}
}

public abstract class AsyncDataSourceView : DataSourceView {

 protected abstract IAsyncResult BeginExecuteSelect(
  DataSourceSelectArguments arguments,
  AsyncCallback asyncCallback,
  object asyncState);

 protected abstract IEnumerable EndExecuteSelect(
  IAsyncResult asyncResult);

  protected override IEnumerable ExecuteSelect(
   DataSourceSelectArguments arguments) {
    //实现从 DataSourceView 中继承的
    //抽象 ExecuteSelect 方法,
    //方法是使用 BeginExecuteSelect 和 EndExecuteSelect,
    //以便通过阻止来
    //进行同步数据访问。
   }

   private IAsyncResult OnBeginSelect(object sender,
     EventArgs e, AsyncCallback asyncCallback,
     object extraData);
   private void OnEndSelect(IAsyncResult asyncResult);

   public override void Select(DataSourceSelectArguments arguments,
    DataSourceViewSelectCallback callback) {
     if (_owner.IsAsync) {
      //使用 OnBeginSelect 和 OnEndSelect
      //作为 BeginEventHandler 和 EndEventHandler 方法,
      //来调用 Page.RegisterAsyncTask,
      //以指明需要
      //进行异步工作。这些方法将依次
      //调用特定的
      //数据源实现,方法是调用
      //已在此类中引入的
      //抽象 BeginExecuteSelect 和 EndExecuteSelect
      //方法。
     }
     else {
      //执行同步数据访问
      base.Select(arguments, callback);
     }
    }
   ...
}

  示例

  现在,新的 AsyncWeatherDataSource 将从 AsyncDataSourceControl 中派生,而 AsyncWeatherDataSourceView 将从 AsyncDataSourceView 中派生。

public class AsyncWeatherDataSource : AsyncDataSourceControl {

//与 WeatherDataSource 相同
}

private sealed class AsyncWeatherDataSourceView : AsyncDataSourceView {
private AsyncWeatherDataSource _owner;
private WeatherService _weatherService;

public AsyncWeatherDataSourceView(AsyncWeatherDataSource owner,
string viewName)
: base(owner, viewName) {
_owner = owner;
}

protected override IAsyncResult BeginExecuteSelect(DataSourceSelectArguments arguments,
AsyncCallback asyncCallback,
object asyncState) {
arguments.RaiseUnsupportedCapabilitiesError(this);

string zipCode = _owner.GetSelectedZipCode();
if (zipCode.Length == 0) {
return new SynchronousAsyncSelectResult(/* selectResult */
null,
asyncCallback, asyncState);
}

_weatherService = new WeatherService(zipCode);
return _weatherService.BeginGetWeather(asyncCallback, asyncState);
}

protected override IEnumerable EndExecuteSelect(IAsyncResult asyncResult) {
SynchronousAsyncSelectResult syncResult =
asyncResult as SynchronousAsyncSelectResult;
if (syncResult != null) {
return syncResult.SelectResult;
}
else {
Weather weatherObject =
_weatherService.EndGetWeather(asyncResult);
_weatherService = null;

if (weatherObject != null) {
return new Weather[] { weatherObject };
}
}

return null;
}
}

  要注意的关键问题是,在使用该框架时,只需要实现 BeginExecuteSelect 和 EndExecuteSelect。在它们的实现过程中,通常要调用由该框架中的各种对象(例如 WebRequest 或 IO 流)所揭示的 BeginXXX 和 EndXXX 方法(在 Visual Studio 2005 中,还需要调用 SqlDataCommand),并返回 IAsyncResult。在此示例中,有一个封装了基础 WebRequest 对象的 WeatherService 帮助程序类。

  对于那些实际缺少异步模式的框架,您在此会看到有效的异步模式;以及您要实现的 BeginExecuteSelect 和 EndExecuteSelect,和您要调用以返回 IAsyncResult 实例的 Begin 和 End 方法。

  最有趣的可能是 SynchronousAsyncSelectResult 类(在某种程度上而言是一种矛盾)。此类是框架附带的。它基本上是一个 IAsyncResult 实现,可使数据立即可用,并从其 IAsyncResult.CompletedSynchronously 属性报告 true。到目前为止,这仅适用于未选择邮政编码的情况,并且需要返回 null(启动异步任务而只返回 null 是没有意义的),但正如您会在下文中看到的,这在其他方案中也是有用的。

  页面基础结构隐藏了在 Microsoft ASP.NET 上下文中执行异步工作的大部分详细信息。希望在此提供的框架使您执行最少的操作就能编写使用此基础结构的数据源。不过,就其本质而言,实现异步行为是复杂的。有时候,第一次阅读本文时会有一些疑问,而第二次阅读时可能就明白了。您可以使用下面“我的评论”表单来发送问题或进行讨论。

ASP.NET2.0中数据源控件之异步数据访问相关推荐

  1. 深度解析ASP.NET2.0中的Callback机制

    callback的一般使用方法还算简单,直接参照msdn的帮助和范例就足够了.但是想要真正用好.用精,或者想开发一些基于callback机制的WEB组件,那么,就要先深入了解callback的实现机制 ...

  2. ASP.NET2.0中的全球化与本地化UICulture,Culture

    ASP.NET2.0中的全球化与本地化UICulture,Culture 来源:转载 日期:2007-2-28 14:59:01 阅读:324 评论:0   一.简介 全球化和本地化是每一位开发者在创 ...

  3. ASP.NET2.0中的ClientScriptManager 类用法—如何添加客户端事件!

    在ASP.NET2.0中,ClientScriptManager 类通过键 String 和 Type 唯一地标识脚本.具有相同的键和类型的脚本被视为重复脚本.因此,我们可以使用脚本类型来避免混淆可能 ...

  4. 在ASP.Net2.0中使用UrlRewritingNet实现链接重写(转)

    在ASP.Net2.0中使用UrlRewritingNet实现链接重写 很多时候我们需要链接转向(Url Rewriting),例如二级域名转向.文章访问链接等场合. 让我们看两个例子: 1 你现在看 ...

  5. 在ASP.Net2.0中使用UrlRewritingNet实现链接重写

    在ASP.Net2.0中使用UrlRewritingNet实现链接重写 很多时候我们需要链接转向(Url Rewriting),例如二级域名转向.文章访问链接等场合. 让我们看两个例子: 1 你现在看 ...

  6. ASP.NET2.0中的ClientScriptManager 类用法—如何添加客户端事件

    在ASP.NET2.0中,ClientScriptManager 类通过键 String 和 Type 唯一地标识脚本.具有相同的键和类型的脚本被视为重复脚本.因此,我们可以使用脚本类型来避免混淆可能 ...

  7. ASP.NET2.0中themes、Skins轻松实现网站换肤!

    ASP.NET2.0中themes.Skins轻松实现网站换肤! 可能有些朋友还不是很清楚themes.skins.下面先介绍下themes.skins.. 一.简介: 一看Themes.Skins这 ...

  8. [导入]ASP.NET2.0中Tabs的简单实现

    摘要: ASP.NET2.0中Tabs的简单实现  阅读全文 [新闻]"Wintel"联盟已名存实亡 文章来源:http://www.cnblogs.com/gyche/archi ...

  9. asp.net2.0中的ValidationGroup (转)

    asp.net2.0中的ValidationGroup 在asp.net 1.1中,对于验证类控件,在使用时,遇到有的不需要验证的控件时,是十分麻烦的,就是说不可能有选择验证某些控件,而在asp.ne ...

最新文章

  1. 函授计算机与科学论文,函授计算机科学与技术论文
  2. QML for Android 加载图片资源的几种方式
  3. java 重建二叉树_【剑指offer】 Java实现重建二叉树
  4. 算法:输入一个链表,输出该链表中倒数第k个结点。
  5. 标记三维点_便携式3D扫描仪全自动三坐标测量机三维扫描设计扫描测量摄影
  6. 吃掉那只青蛙_每日可交付成果–吃青蛙的艺术
  7. 二分法04:猜数字大小
  8. 22. Window print() 方法
  9. springboot 整合JWT token验证机制
  10. alsa buffer原理_alsa音频开发全攻略
  11. SPSS应用——时间序列分析
  12. 深度学习、机器学习交流群
  13. 【华人学者风采】聂飞平 西北工业大学
  14. 信息系统分析与设计 第十章 系统总体设计
  15. 怎样打印微信文档文件?
  16. 用Python ttkbootstrap 带你制作账户注册信息界面
  17. PT100(RTD)三线制四线制测量方案
  18. java反射 枚举_Java反射应用之获取枚举类的枚举
  19. 使用Ventoy安装Deepin系统出现Error verification failed 0x1A Security violation错误
  20. XSL 和 XSLT的区别

热门文章

  1. 驱动12.移植dm9000驱动程序
  2. 开发环境配置--Ubuntu+Qt4+OpenCV(二)
  3. 基于Discuz的原生态MVC框架Uxf
  4. 修改zepto源代码,使支持wp8的ie10
  5. 4个人的学校(转载)
  6. JSValidation 1.0b4 发布了!
  7. perl 的 localtime、timelocal、strftime关于时间的函数
  8. iOS逆向之自动化重签名
  9. 2018年预测:GPU数据库或是未来的数据库统治者!
  10. Kivy: Crossplatform Framework for NUI