在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
看这里: 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 “异步点”的东西来决定的。
public partial class MyPages : System.Web.UI.Page
{ 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; } } } 但是当我们要同时处理多个异步任务,我们怎么做呢?通常
void Page_Load (object sender, EventArgs e)
{ 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) 当我们再执行下列代码时,会发现始终只启动了一个线程。
void Page_Load (object sender, EventArgs e)
{ 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 时,在所有异步任务完成之前,执行页的线程将被阻止。 任何在 ExecuteRegisteredAsyncTasks 方法显式执行。ExecuteRegisteredAsyncTasks 方法也可用于在 PreRenderComplete 事件之前启动任务。ExecuteRegisteredAsyncTasks 方法执行页上所有未执行的注册异步任务。 默认情况下,如果异步任务未在 45 秒钟内完成,则它将超时。您可在 Web.config 文件或页指令中指定不同的超时值。Web.config 文件的 <pages> 节包含 asyncTimeout 属性,如下所示。 <system.web> <pages asyncTimeout="30"> </pages> </system.web> 页指令包含 AsyncTimeout 属性。 <%@ Page AsyncTimeout="30" %> 同样的功能,更简洁的代码:
public partial class RssAsync : System.Web.UI.Page
{ 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. |
请发表评论