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会将请求带入异步管道进行实际的页面执行。

Asynchronous Pages in ASP.NET 2.0_第1张图片

此时我们发现在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 的时候我们会发现:

Asynchronous Pages in ASP.NET 2.0_第2张图片

启动了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 时,在所有异步任务完成之前,执行页的线程将被阻止。

任何在 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" %>

同样的功能,更简洁的代码:

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();
    }
    
}

DownLoad

了解更多关于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.

你可能感兴趣的:(asp.net)