Asynchronous Pages in ASP.NET 2.0
看这里: http://msdn.microsoft.com/en-us/magazine/cc163725.aspx
ASP.NET2.0 异步页面技术是用来解决页面执行长时间,复杂逻辑代码所造成的页面长时间不呈现。它与我们平常说Ajax技术有着很大区别。
ASP.NET2.0异步技术采用.Net framework的多线程技术来解决的。当我们在ASP.NET页面中标记Async='True'时,页面编译器将会自动编译成异步类并实现IHttpasynchandler. 同时ASPNET_ISAPI会将请求带入异步管道进行实际的页面执行。

此时我们发现在Page_PreRender事件之后,PreRenderComplete事件之前,它启动了一个后台线程来执行相应的任务。为什么会选择在这个事件时候发生,并且后台线程怎么找到并返回结果的呢?那是因为有个叫做Async point “异步点”的东西来决定的。
{
private const string RSSFEED = "http://weblogs.asp.net/despos/rss.aspx";
private WebRequest weq;
protected void Page_Load(object sender, EventArgs e)
{
AddOnPreRenderCompleteAsync(new BeginEventHandler(BeginResult),
new EndEventHandler(EndTask));
}
IAsyncResult BeginResult(Object src, EventArgs args, AsyncCallback cb, Object state)
{
Trace.Warn("custom message","Begin async:thread=" + Thread.CurrentThread.ManagedThreadId.ToString());
weq = WebRequest.Create(RSSFEED);
return weq.BeginGetResponse(cb, state);
}
void EndTask(IAsyncResult ar)
{
string text;
using (WebResponse response = weq.EndGetResponse(ar))
{
StreamReader reader;
using (reader = new StreamReader(response.GetResponseStream()))
{
text = reader.ReadToEnd();
}
Literal1.Text = text;
}
}
}
但是当我们要同时处理多个异步任务,我们怎么做呢?通常
{
AddOnPreRenderCompleteAsync (
new BeginEventHandler(BeginTask),
new EndEventHandler(EndTask));
AddOnPreRenderCompleteAsync(
new BeginEventHandler(BeginTask1),
new EndEventHandler(EndTask1));
AddOnPreRenderCompleteAsync(
new BeginEventHandler(BeginTask1),
new EndEventHandler(EndTask1));
}
但是,当我们启动Trace 的时候我们会发现:
启动了2个线程,异步页面只有所有的请求返回。也就意味着如果我们写N个异步调用就启动N个异步线程,并且如果任何其中一个卡死,那页面就会block掉直到超时.
当然那样是不好的,其实面对这样的问题,我们都需要自定义IAsyncResult.在内部,我们可以控制是否所有的任务都完成才返回,具体实现请下载代码查看(CompositeAsyncResult.cs)
当我们再执行下列代码时,会发现始终只启动了一个线程。
{
AddOnPreRenderCompleteAsync (
new BeginEventHandler(BeginTask),
new EndEventHandler(EndTask));
}
IAsyncResult BeginTask(object sender, EventArgs e, AsyncCallback cb, object state)
{
// Create the custom AsyncResult object
CompositeAsyncResult ar = new CompositeAsyncResult(cb, state, 2);
// Fire the first request
req1 = WebRequest.Create(RSSFEED1);
ar1 = req1.BeginGetResponse(ar.Callback, state);
// Fire the second request
req2 = WebRequest.Create(RSSFEED2);
ar2 = req2.BeginGetResponse(ar.Callback, state);
return ar;
}
同时,我要提一下PageAsyncTask方法:
看看MSDN上的解释,我们就会发现,它是独立Asynchronous 页面的。就算你将页面的Async=‘false’,它一样的实行异步任务,只是将会阻塞页面线程。
ASP.NET 版本 2.0 允许您注册多个任务到页,并在呈现页之前异步运行这些任务。如果任务进程缓慢,且您不希望在执行它时拖延其他进程,则您可指定异步运行该任务。异步任务可并行或顺序执行。
PageAsyncTask 对象必须通过 RegisterAsyncTask 方法注册到页。页本身无需异步处理以执行异步任务。您可在页指令上将 Async 属性设置为 true(如下面的代码示例所示)或 false,异步任务将仍然异步处理:
<%@ Page Async="true" %>
当 Async 属性设置为 false 时,在所有异步任务完成之前,执行页的线程将被阻止。
任何在 PreRenderComplete 事件之前注册的异步任务如果还未执行,则将由页自动执行。在 PreRenderComplete 事件之后注册的异步任务必须通过 ExecuteRegisteredAsyncTasks 方法显式执行。ExecuteRegisteredAsyncTasks 方法也可用于在 PreRenderComplete 事件之前启动任务。ExecuteRegisteredAsyncTasks 方法执行页上所有未执行的注册异步任务。
默认情况下,如果异步任务未在 45 秒钟内完成,则它将超时。您可在 Web.config 文件或页指令中指定不同的超时值。Web.config 文件的 <pages> 节包含 asyncTimeout 属性,如下所示。
<system.web>
<pages asyncTimeout="30">
</pages>
</system.web>
页指令包含 AsyncTimeout 属性。
<%@ Page AsyncTimeout="30" %>
同样的功能,更简洁的代码:
{
private const string RSSFEED1 = "http://weblogs.asp.net/despos/rss.aspx";
private const string RSSFEED2 = "http://blogs.ugidotnet.org/dinoes/rss.aspx";
RssFeedAsyncReader rss1, rss2;
public string rssData;
void Page_Load (object sender, EventArgs e)
{
this.PreRenderComplete += new EventHandler(RssAsync_PreRenderComplete);
rss1 = new RssFeedAsyncReader(RSSFEED1);
rss2 = new RssFeedAsyncReader(RSSFEED2);
PageAsyncTask task1 = new PageAsyncTask(
new BeginEventHandler(rss1.BeginRead),
new EndEventHandler(rss1.EndRead),
null,
null,
true);
PageAsyncTask task2 = new PageAsyncTask(
new BeginEventHandler(rss2.BeginRead),
new EndEventHandler(rss2.EndRead),
null,
null,
true);
RegisterAsyncTask(task1);
RegisterAsyncTask(task2);
}
void RssAsync_PreRenderComplete(object sender, EventArgs e)
{
rssData = rss1.GetRssData() + rss2.GetRssData();
}
}
了解更多关于PageAsyncTask,点击:http://msdn.microsoft.com/zh-cn/library/system.web.ui.pageasynctask(VS.80).aspx
到了这里,我们会有些疑问,到底用哪个方法(AddOnPreRenderCompleteAsync还是RegisterAsyncTask)适合呢?他们有什么区别呢?
相同点: 从功能上讲,他们是相同的,页面请求的执行都分为2个阶段,在异步点(Async point)之前和之后.
不同点:
1. RegisterAsyncTask 是被设计用来运行页面类的异步任务的API。不仅仅是异步页面。AddOnPreRenderCompleteAsync 是专门用来执行异步页面的API。
2. One is that RegisterAsyncTask executes the End handler on a thread with a richer context than AddOnPreRenderCcompleteAsync. The thread context includes impersonation and Httpcontext information that is missing in the thread serving the End handler of a classic asynchronous page. In addition, RegisterAsyncAsyncTask allow you to set a timeout to ensure that any task doesn't run for more than a given number of seconds.
The other difference is that RegisterAsyncTask makes the implementation of multiple calls to remote sources significantly easier. You can have parallel execution by simply setting a Boolean flag, and you don't need to create and manage your own IAsyncResult object.
The bottom line is that you can use either approach for a single task, but you should opt for RegisterAsyncTask when you have multiple task to execute simultancely.
浙公网安备 33010602011771号