asp.net| Access | control | data | Data Source | asynchronous
Summary: This is the third in a series of articles that introduce data source controls. In this article, Nikhil focuses on how to perform and encapsulate asynchronous data access while demonstrating a reusable asynchronous data access framework that is based on the features available in Microsoft Visual Studio 2005.
In parts 1th and 2nd , the WeatherDataSource control is established, which runs against the XML APIs provided by Weather.com (English), using WebRequest and Webrespon SE to access data over HTTP. To date, the service has been accessed synchronously. As a result, page processing is blocked until the WEB request completes. This method is valid for test pages and can be effective on small sites, but will fail miserably on sites that receive large amounts of traffic, such as portal pages, where weather modules can be very common.
Introduction
There are a large number of threads in the thread pool that can be used for service requests, but unfortunately the solution is not just to increase the limit (it will also increase the amount of resources the thread consumes and the CPU consumes). Therefore, when a page is blocked and waits for another server, it is still consuming threads, which may cause other incoming requests to wait longer in the queue. This will result in slower access to the site and lower CPU utilization. In Visual Studio 2005, we introduced asynchronous pages, which enabled the control to define the tasks that they wanted to accomplish asynchronously, that is, the thread that was used to process the request was not blocked. The details of the asynchronous page itself will not be described here, as previously described in both Dmitry (English) and Fritz Onion. Here's how to take advantage of this feature in a data source control and use the Add-in framework to implement an asynchronous data source.
Background
In the 1th part , it refers indirectly to the odd design of the DataSourceView class:
Public abstract class DataSourceView {
public virtual void Select (datasourceselectarguments arguments,
DataSourceViewSelectCallback callback);
Protected abstract IEnumerable ExecuteSelect (
DataSourceSelectArguments arguments);
...
}
You will notice that the public Select method does not actually return any data. Instead, it accepts a callback and returns the data through that callback. It invokes only the protected ExecuteSelect, which always performs synchronous data access, to retrieve data to be returned to the data-bound control. The default implementation of the DataSourceView class does not actually perform any operations asynchronously. The reason is that there is no out-of-the-box asynchronous data source control. But the design of the OM does allow asynchronous data access, under which data is not available until the asynchronous work completes. So we have a callback based model.
Those familiar with the asynchronous APIs in the framework will notice the lack of an asynchronous Pattern: The public Select, Beginselect, and Endselect methods, in which the data-bound control chooses which methods to invoke. However, data-bound controls do not determine whether to choose the synchronization API or the asynchronous API. In addition, adding properties on data-bound controls has no effect. The data source control encapsulates details about how to access the data store, and whether the access to the data store occurs synchronously or asynchronously should be determined according to the data source based on semantics or based on the custom attribute. The correct location for the potential "bool Performasyncdataaccess" attribute is appropriate for the data source control itself. This also enables data source controls to perform data access using a single method, even if multiple data-bound controls are bound to the same data source. This has been explained many times by the subtle concepts of the architecture, and I wish to clarify the design.
The last thing to note about asynchronous tasks is whether the page should perform any asynchronous work that the page developer ultimately decides (through the Async attribute of the page directive). As a result, any well-written data source control must degrade to perform synchronized data access as needed.
Framework
In this framework (which is illustrated by the remainder of the example in this series), the Asyncdatasource and AsyncDataSourceView base classes are placed together to implement data source controls that can perform asynchronous data access. The following is an overview of the framework and some of the comments that help clarify its meaning:
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) {
Implements the DataSourceView inherited from the
Abstract ExecuteSelect method,
The method is to use BeginExecuteSelect and EndExecuteSelect,
So that by stopping to
For synchronous data access.
}
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) {
Using Onbeginselect and Onendselect
As a BeginEventHandler and EndEventHandler method,
To invoke Page.registerasynctask,
To indicate the need
To work asynchronously. These methods will sequentially
Invokes a specific
Data source implementation by calling the
that have been introduced in this class.
Abstract BeginExecuteSelect and EndExecuteSelect
Method.
}
else {
Performing Synchronous data access
Base. Select (arguments, callback);
}
}
...
}
Example
The new AsyncWeatherDataSource is now derived from the AsyncDataSourceControl, and AsyncWeatherDataSourceView is derived from AsyncDataSourceView.
public class Asyncweatherdatasource:asyncdatasourcecontrol {
Same as 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;
}
}
The key issue to note is that when you use the framework, you only need to implement BeginExecuteSelect and EndExecuteSelect. During their implementation, it is common to invoke the BeginXXX and EndXxx methods that are revealed by various objects in the framework (such as WebRequest or IO streams) (in Visual Studio 2005, also call Sqldatacommand) and return IAsyncResult. In this example, there is a WeatherService helper class that encapsulates the underlying WebRequest object.
For those frameworks that actually lack asynchronous patterns, you'll see a valid asynchronous Pattern here, as well as the BeginExecuteSelect and endexecuteselect you want to implement, and the Begin and end methods that you want to call to return the IAsyncResult instance.
Perhaps the most interesting is the SynchronousAsyncSelectResult class (in some ways a paradox). This class is included with the framework. It is basically a IAsyncResult implementation that makes data available immediately and reports true from its Iasyncresult.completedsynchronously property. So far, this applies only to cases where no postal code has been selected, and the need to return null (it makes no sense to start the asynchronous task and return only null), but as you will see later, this is useful in other scenarios as well.
The page infrastructure hides most of the details of performing asynchronous work in the context of Microsoft asp.net. The framework that you want to provide here allows you to write a data source that uses this infrastructure with minimal action. However, in its nature, the implementation of asynchronous behavior is complex. Sometimes, the first time you read this article there will be some questions, and the second reading may be understood. You can use the "my comments" form below to send a question or discuss it. Please wait for more performance data access (to be covered in the next article).