Monday, August 30, 2010

How to register asynchronous task in asp.net page execution

Why we need asynchronous tasks?

Execute a time consuming operations in parallel to the CLR thread which execute the request

If you have long running operations to execute in the page execution, you can execute them in parallel rather than serial execution. The difference between page asynchronous task and firing up a separate thread is, page will NOT get rendered until all the page asynchronous tasks get completed but if you handle part of your execution to a separate thread, page get rendered regardless of external thread completed or not.
There are two major points that we may need to understand when registering asynchronous with page execution.
Asynchronous Result – A class which implements IAsyncResult interface, which can be found at the end of this post.
  1. Asynchronous Result – A class which implements IAsyncResult interface, which can be found at the end of this post.
  2. Separate work item queued in the ThreadPool which execute the time consuming operation

Page:
Demonstrate how to register page asynchronous task using custom PageAsyncResult class which implements the IAsyncResult interface.
public partial class Test : Page
{
    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
        this.Response.Write("Executing Init...<br />");
        PageAsyncTask task1 = new PageAsyncTask(OnBegin, OnEnd, OnTimeOut, null);
        this.RegisterAsyncTask(task1);
    }
    private void PerformAsyncWork(Object state)
    {
        PageAsyncResult result = state as PageAsyncResult;
        try
        {
            ///
            /// Do your time consuming operation here
            /// Folloing is a fake time consuming operation
            /// Only for the demonstration
            ///
            result.Context.Response.Write("Executing time consuming operation...<br />");
            for (int i = 0; i < 5; i++)
                Thread.Sleep(1000);
            result.Context.Response.Write("Finised executing time consuming operation...<br />");
        }
        catch (Exception e)
        {
            result.Context.AddError(e);
        }
        finally
        {
            result.Complete(false);                
        }
    }
    private IAsyncResult OnBegin(Object sender, EventArgs e, AsyncCallback callback, Object state)
    {
        IAsyncResult result = new PageAsyncResult(callback, HttpContext.Current);
        ThreadPool.QueueUserWorkItem(PerformAsyncWork, result);
        return result;
    }
    private void OnEnd(IAsyncResult result)
    {
    }
    private void OnTimeOut(IAsyncResult result)
    {
    }
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        this.Response.Write("Executing Load...<br/>");
    }
}


PageAsyncResult class:
PageAsyncResult class which implements IAsyncResult interface.  This class contains HttpContext what we can use in the asynchronous to manipulate response, request, session etc.
public class PageAsyncResult : IAsyncResult
{
    #region Attributes
        
    private AsyncCallback callback;
    private HttpContext context;
    private bool completed;
    private bool completedSynchronously;
 
    #endregion
 
    #region IAsyncResult Members
 
    bool IAsyncResult.IsCompleted { get { return completed; } }
    Object IAsyncResult.AsyncState { get { return null; } }
    WaitHandle IAsyncResult.AsyncWaitHandle { get { return null; } }
    bool IAsyncResult.CompletedSynchronously
    {
        get { return completedSynchronously; }
    }
 
    #endregion
 
    #region Properties
        
    public HttpContext Context
    {
        get
        {
            if (completed || context == nullthrow new InvalidOperationException();
            return context;
        }
    }
    #endregion
 
    #region Methods
        
    public PageAsyncResult(AsyncCallback cb, HttpContext context)
    {
        callback = cb;
        this.context = context;
    }
    public void Complete(bool synchronous)
    {
        completed = true;
        completedSynchronously = synchronous;
        context = null;
        if (callback != null)
            callback(this);
    }
 
    #endregion
}

AddOnPreRenderCompleteAsync vs RegisterAsyncTask 

The System.Web.UI.Page class introduces another method to facilitate asynchronous operations: AddOnPreRenderCompleteAsync. RegisterAsyncTask has four advantages over AddOnPreRenderCompleteAsync. First, in addition to Begin and End methods, RegisterAsyncTask lets you register a timeout method that's called if an asynchronous operation takes too long to complete. You can set the timeout declaratively by including an AsyncTimeout attribute in the page's @ Page directive. AsyncTimeout="5" sets the timeout to 5 seconds. The second advantage is that you can call RegisterAsyncTask several times in one request to register several async operations. As with MethodAsync, ASP.NET delays rendering the page until all the operations have completed. Third, you can use RegisterAsyncTask's fourth parameter to pass state to your Begin methods. Finally, RegisterAsyncTask flows impersonation, culture, and HttpContext.Current to the End and Timeout methods. As mentioned earlier in this discussion, the same is not true of an End method registered with AddOnPreRenderCompleteAsync.

Reference 1 - MSDN:
Reference 2 - MSDN:

No comments:

iPhone Launch Screen Sizes

iPhone Portrait iOS 8 Retina HT 5.5 = 1242 X 2208 Retna HD 4.7 = 750 X 1134 iPhone Landscape iOS 8 Retina HD 5.5  2208 X 1242 iPho...