At today's .NET user group meeting someone asked about doing async tasks in an ASP.NET page and not blocking. Here is one option in all it's g(l)ory:
The ASPX @page directive gains a AsyncTimeOut="3" which will make it wait up to 3 seconds for the async task to complete. Since the operation itself does not actually use an external resource, a fake out of the AsyncResult is done using a delegate and a BeginInvoke on it which yields the IAsyncResult that BeginEventHandler is expected to return and EndEventHandler requires. If the work was actually a http web request or something, it would have a BeginInvoke provided by the proxy.
The code in front:
==============================
<%@ Page Language="C#"
AutoEventWireup="true"
CodeFile="Default.aspx.cs"
Inherits="_Default"
Async="true"
AsyncTimeOut="3"
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Async processing</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Literal runat="server" ID="Output"></asp:Literal>
</div>
</form>
</body>
</html>
==============================
and the code behind:
==============================
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class _Default : System.Web.UI.Page
{
protected delegate void DoTheWorkDelegate();
private DoTheWorkDelegate _doTheWorkDelegate;
private TimeSpan _workTime = TimeSpan.FromSeconds(2);
private string _report = ">";
public string Report
{
get { return _report; }
set { _report += value + "... "; }
}
protected void Page_Load(object sender, EventArgs e)
{
if (! String.IsNullOrEmpty( Request.QueryString["t"]))
{
_workTime = TimeSpan.FromSeconds(double.Parse(Request.QueryString["t"]));
}
PageAsyncTask task = new PageAsyncTask(
new BeginEventHandler(BeginAsyncOp),
new EndEventHandler(EndAsyncOp),
new EndEventHandler(TimedOutOp),
null);
RegisterAsyncTask(task);
Report = "page load completed";
}
protected override void Render(HtmlTextWriter wr)
{
Output.Text = Report;
base.Render(wr);
}
IAsyncResult BeginAsyncOp(object sender, EventArgs e, AsyncCallback cb, object state)
{
this.Report = "Begin Async";
_doTheWorkDelegate = new DoTheWorkDelegate(doTheWork);
return _doTheWorkDelegate.BeginInvoke(cb,state);
}
void EndAsyncOp(IAsyncResult ar)
{
Report = "End Async";
}
void TimedOutOp(IAsyncResult ar)
{
Report = "Timed Out";
}
void doTheWork()
{
System.Threading.Thread.Sleep(_workTime);
}
}