熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

ASP.NET2.0中數據源控件之異步數據訪問

2013-11-13 10:14:25  來源: .NET編程 

  在第 部分和第 部分中建立了 WeatherDataSource 控件該控件針對 (英文)所提供的 XML API 來運行使用 WebRequest 和 WebResponse 來通過 HTTP 訪問數據迄今為止均是同步訪問該服務因此頁面處理被阻止直到 Web 請求完成為止此方法對於測試頁面是有效的在小站點上也可能有效但是在接收大量通信流量的站點上則會慘敗例如門戶頁面天氣模塊在其中可能非常常見 
   
  引言 
   
  在線程池中有固定不變的大量線程可用於服務請求遺憾的是該解決方案並非僅僅提高限制(還會增加線程占用資源以及 CPU 占用資源)因此當一個頁面被阻止而等候另一個服務器時它還在占用線程因而可能會導致其他傳入的請求在隊列中等候更長的時間這將導致對站點的訪問變慢並降低 CPU 的利用率在 Visual Studio 我們引入了異步頁面這使得控件能夠定義它們希望異步完成的任務無需阻止用來處理請求的線程在此將不介紹異步頁面本身的詳細信息Dmitry(英文)和 Fritz Onion(英文)中以前已經有所介紹此處要介紹的是如何在數據源控件中利用此功能使用加載項框架來實現異步數據源 
   
背景 
   
  在第 部分中間接提到了 DataSourceView 類的有些古怪的設計
  
  public abstract class DataSourceView {
   public virtual void Select(DataSourceSelectArguments arguments
    DataSourceViewSelectCallback callback);
   protected abstract IEnumerable ExecuteSelect(
    DataSourceSelectArguments arguments);
   
  } 
   
  您會注意到公共 Select 方法實際上並不返回任何數據而是接受一個回撥並通過該回撥來返回數據它只調用受保護的 ExecuteSelect(它始終執行同步數據訪問)來檢索要退還給數據綁定控件的數據DataSourceView 類的默認實現實際上不會異步執行任何操作原因在於並不存在任何現成的異步數據源控件但 OM 的設計確實允許實現異步數據訪問在這種設計下數據在異步工作完成之後才可用因此我們就有了一個基於回撥的模型 
   
  那些熟悉框架中的異步 API 的人會注意到缺少了異步模式公共 SelectBeginSelect 和 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 IAsyncDataSourceIsAsync {
   get { return _performAsyncDataAccess && PageIsAsync; }
  }
  }
  
  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 (_ownerIsAsync) {
        //使用 OnBeginSelect 和 OnEndSelect
        //作為 BeginEventHandler 和 EndEventHandler 方法
        //來調用 PageReGISterAsyncTask
        //以指明需要
        //進行異步工作這些方法將依次
        //調用特定的
        //數據源實現方法是調用
        //已在此類中引入的
        //抽象 BeginExecuteSelect 和 EndExecuteSelect
        //方法
       }
       else {
        //執行同步數據訪問
        baseSelect(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) {
  argumentsRaiseUnsupportedCapabilitiesError(this);
  
  string zipCode = _ownerGetSelectedZipCode();
  if (zipCodeLength == ) {
  return new SynchronousAsyncSelectResult(/* selectResult */
  null
  asyncCallback asyncState);
  }
  
  _weatherService = new WeatherService(zipCode);
  return _weatherServiceBeginGetWeather(asyncCallback asyncState);
  }
  
  protected override IEnumerable EndExecuteSelect(IAsyncResult asyncResult) {
  SynchronousAsyncSelectResult syncResult =
  asyncResult as SynchronousAsyncSelectResult;
  if (syncResult != null) {
  return syncResultSelectResult;
  }
  else {
  Weather weatherObject =
  _weatherServiceEndGetWeather(asyncResult);
  _weatherService = null;
  
  if (weatherObject != null) {
  return new Weather[] { weatherObject };
  }
  }
  
  return null;
  }
  } 
   
  要注意的關鍵問題是在使用該框架時只需要實現 BeginExecuteSelect 和 EndExecuteSelect在它們的實現過程中通常要調用由該框架中的各種對象(例如 WebRequest 或 IO 流)所揭示的 BeginXXX 和 EndXXX 方法(在 Visual Studio 還需要調用 SqlDataCommand)並返回 IAsyncResult在此示例中有一個封裝了基礎 WebRequest 對象的 WeatherService 幫助程序類 
   
  對於那些實際缺少異步模式的框架您在此會看到有效的異步模式以及您要實現的 BeginExecuteSelect 和 EndExecuteSelect和您要調用以返回 IAsyncResult 實例的 Begin 和 End 方法 
   
  最有趣的可能是 SynchronousAsyncSelectResult 類(在某種程度上而言是一種矛盾)此類是框架附帶的它基本上是一個 IAsyncResult 實現可使數據立即可用並從其 IAsyncResultCompletedSynchronously 屬性報告 true到目前為止這僅適用於未選擇郵政編碼的情況並且需要返回 null(啟動異步任務而只返回 null 是沒有意義的)但正如您會在下文中看到的這在其他方案中也是有用的 
   
  頁面基礎結構隱藏了在 Microsoft 上下文中執行異步工作的大部分詳細信息希望在此提供的框架使您執行最少的操作就能編寫使用此基礎結構的數據源不過就其本質而言實現異步行為是復雜的有時候第一次閱讀本文時會有一些疑問而第二次閱讀時可能就明白了您可以使用下面我的評論表單來發送問題或進行討論


From:http://tw.wingwit.com/Article/program/net/201311/13019.html
  • 上一篇文章:

  • 下一篇文章:
  • 推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.