All,
One of the largest problems I see in people implementing Async pages is that they create dependencies between the target Async operation type (ADO.NET, WebRequest, etc.) and the ASP.NET UI code.
To get around this (which is highly recommended) simply do the following:
1) Create a private delegate in your ASP.NET page
2) Use this delegate to wrap the operation (which is likely in a different assembly). This operation can also be Async, but it is irrelevant for the most part.
Here is a sample.
We want to get some XML from a URL, modify the XML and return it to the browser with a new XSLT transform so the browser can transform the data.
Here is the ASP.NET page:
Page Async=”true” Language=”C#” AutoEventWireup=”true” CodeFile=”GetFormattedJobListings.aspx.cs” Inherits=”GetFormattedJobListings”
On the Page_Load event I only want this hooked up on a postback:
public partial class GetFormattedJobListings : System.Web.UI.Page
{
delegate String GetAsyncResults(String URL);
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
AddOnPreRenderCompleteAsync(new BeginEventHandler(BeginAsyncOperation),
new EndEventHandler(EndAsyncOperation));
}
}
OK so we have the plumbing in place. Now let’s define the two delegates that will be called:
NOTE: See how we do not reference anything but a service/domain layer, keeping our dependencies intact:
IAsyncResult BeginAsyncOperation(object sender, EventArgs e, AsyncCallback cb, object state)
{
StringBuilder oSB = new StringBuilder();
String strXMLResponse;
HTTPServicesAsync oGetXML = new HTTPServicesAsync();
oSB.Append(ConfigurationManager.AppSettings["JobDataURL"].ToString());
oSB.Append(“abbr=” + cmbSites.SelectedValue);
oSB.Append(“&format=xml&count=20″);
GetAsyncResults oAsync = new GetAsyncResults(oGetXML.GetHTTPContentFromURL);
// NOTE: We return this from OUR delegate not some .NET Type Intrinsic
return oAsync.BeginInvoke(oSB.ToString(), cb, state);
}
Then all we have to do is handle the page response:
void EndAsyncOperation(IAsyncResult itfAR)
{
String _xmlContent;
XMLServices oXML = new XMLServices();
AsyncResult ar = (AsyncResult)itfAR;
GetAsyncResults GetXML = (GetAsyncResults)ar.AsyncDelegate;
if (chkUseNew.Checked)
oXML.OverrideURL = ConfigurationManager.AppSettings["NewSiteURL"].ToString();
_xmlContent = GetXML.EndInvoke(itfAR);
// Now write the aquired XML to the browser
Response.Clear();
Response.ContentType = “text/xml”;
Response.Write(oXML.GetModifiedXml(_xmlContent));
Response.End();
}
Of course we could do this with other techniques, but we would loose the ability to return the thread from the first stage of processing to the thread pool (where it can be used).
I had previously used other techniques, such as checking the IsCompleted, and .waitone, but this is by far the best architectural technique. Just remember not to pollute your UI with dependencies on lower ‘service level’ technologies such as ADO.NET as create your own delegates to get the IAsyncResult you will need.
For example, this article shows examples that in my opinion violate seperation of concerns as the examples directly reference Async operations on things like the BeginExecuteReader.
I recommend the article, but NOT using the types used in the examples. Instead use the technique shown here (in my opinion).
http://msdn.microsoft.com/msdnmag/issues/05/10/WickedCode/
Kind Regards,
Damon Carr



