Asynchronous ASP.NET 2.0 Programming

29 בספטמבר 2008

תגיות: ,
5 תגובות

Asynchronous ASP.NET 2.0 Programming

One of the coolest features in ASP.NET 2.0 is asynchronous pages. This feature increase scalability by using thread-pool threads more efficiently.

With asynchronous pages, a thread which assigned from the thread-pool to process page request, is returned to the thread pool instead of waiting for an I/O operation to complete. This means more threads available to process incoming requests, and when I/O operation is completed, another thread from the pool is guarantee to send back the response.

There are 3 asynchronous programming model in ASP.NET 2.0:

  • Asynchronous Pages
  • Asynchronous HTTP Handlers
  • Asynchronous HTTP Modules

In this post I will cover the asynchronous pages programming model.

Asynchronous Pages in ASP.NET 2.0

Let's start by including an Async="true" attribute in the @Page directive. This tells ASP.NET to implement IHttpAsyncHandler in the page.

<%@ Page="" Async="true" Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>

AddOnPreRenderCompleteAsync

In Page_Load (or any early Page's life time) we can call to the AddOnPreRenderCompleteAsync method, to register begin and end methods, as shown in the following code:

using System;

using System.Configuration;

using System.Data;

using System.Linq;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.HtmlControls;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Xml.Linq;

using System.Net;

using System.IO;

 

public partial class _Default : System.Web.UI.Page

{

    private WebRequest _request;

 

    protected void Page_Load(object sender, EventArgs e)

    {

        AddOnPreRenderCompleteAsync(

            new BeginEventHandler(BeginAsyncOperation),

            new EndEventHandler(EndAsyncOperation)

        );

    }

 

    IAsyncResult BeginAsyncOperation(object sender, EventArgs e,

        AsyncCallback asyncCallback, object state)

    {

        _request = WebRequest.Create("http://blogs.microsoft.co.il/blogs/egady");

 

        return _request.BeginGetResponse(asyncCallback, state);

    }

 

    void EndAsyncOperation(IAsyncResult asyncResult)

    {

        using (WebResponse response = _request.EndGetResponse(asyncResult))

        {

            using (StreamReader reader =

                new StreamReader(response.GetResponseStream()))

            {

                string str = reader.ReadToEnd();

 

                Response.Write(str);

            }

        }

    }

}

The BeginAsyncOperation can launch an asynchronous operation such database call, or web service call, and return immediately. When this operation is completed, another thread continue from the EndAsyncOperation method to complete the request and send the response back to the client!

The result of the code is showing in the following image:

Asynchronous ASP.NET 2.0 Programming 

RegisterAsyncTask

What if you want to perform several asynchronous I/O operations in an asynchronous page which not involved remote web service/database calls? We can call AddOnPreRenderCompleteAsync multiple times, and it will cause the tasks to execute sequentially – next begin method not called until previous end method returns. For concurrent execution it will requires you to compose IAsyncResult.

The RegisterAsyncTask can helps us with this, by calling it multiple times (one per task). The tasks can be executed sequentially or concurrently, and prevent us from implementing IAsyncResult!

The following code cause to the same result like the above sample with AddOnPreRenderCompleteAsync:

using System;

using System.Collections;

using System.Configuration;

using System.Data;

using System.Linq;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.HtmlControls;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Xml.Linq;

using System.Net;

using System.IO;

 

public partial class Default2 : System.Web.UI.Page

{

    private WebRequest _request;

 

    protected void Page_Load(object sender, EventArgs e)

    {

        PageAsyncTask task = new PageAsyncTask(

            new BeginEventHandler(BeginAsyncOperation),

            new EndEventHandler(EndAsyncOperation),

            new EndEventHandler(TimeoutAsyncOperation), null

        );

        RegisterAsyncTask(task);

    }

 

    IAsyncResult BeginAsyncOperation(object sender, EventArgs e,

        AsyncCallback asyncCallback, object state)

    {

        _request = WebRequest.Create("http://blogs.microsoft.co.il/blogs/egady");

 

        return _request.BeginGetResponse(asyncCallback, state);

    }

 

    void EndAsyncOperation(IAsyncResult asyncResult)

    {

        using (WebResponse response = _request.EndGetResponse(asyncResult))

        {

            using (StreamReader reader =

                new StreamReader(response.GetResponseStream()))

            {

                string str = reader.ReadToEnd();

 

                Response.Write(str);

            }

        }

    }

 

    void TimeoutAsyncOperation(IAsyncResult asyncResult)

    {

    }

}

You can decide if the task will run in parallel or sequentially by the fifth parameter of the PageAsyncTask constructor:

  • true – Execute in parallel
  • false – Execute in series

ExecuteRegisteredAsyncTasks – Execute registered async tasks immediately, and synchronously – Please don't use this method!!

Context Flow

Another advantage of RegisterAsyncTask is that it flows request context from begin threads to end threads, and that includes:

  • HttpContext
  • Impersonation
  • Culture

While in AddOnPreRenderCompleteAsync HttpContext.Current will be null in end threads, and end threads also revert to process identity.

Conclusion

Asynchronous programming can make your application more scalable, by using the ASP.NET thread-pool more efficiently. When you take the 5-10 pages in your site, that are used mostly and have the heaviest remote I/O operations, and convert them into asynchronous pages, you can more than double your traffic into your site!

References:

kick it on DotNetKicks.com


הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. (*) שדות חובה מסומנים

5 תגובות

  1. Guy Soffer29 בספטמבר 2008 ב 11:54

    WOW, your blog is alive, cool!

    להגיב
  2. alikl29 בספטמבר 2008 ב 15:31

    very good stuff – thanks for sharing!
    I am working with the customer and we hitting exactly this topic. Very useful!

    להגיב
  3. Mansoor Sadat7 בפברואר 2009 ב 1:19

    Hello,
    I tried the first piece of code. However, on my end I am not getting results asynchronously. I could have the definition of asynchronous wrong; from what I understand, the web page should load instantly and a process (in this case getting results from your blog page) should run in background and display results when they are available.

    When I run the code above, it looks like any normal page.

    Can you let me know if I am looking in the wrong place? Or, am I missing something? I do have the Async attribute in the Page directive and the rest of the code I copied and pasted into VS.

    להגיב
  4. egady10 בפברואר 2009 ב 16:46

    In client side it is synchronous, while the asynchronous behavior is only at the server side, to avoid threads from waiting to complete the request. So if you seek for asynchronously behavior in the client side, seach for AJAX technology.

    להגיב
  5. Ryan_Zim22 ביולי 2009 ב 14:46

    Maybe you could put me in the right track, this seems to be close to what I am trying to do.

    I want to have a listbox updating as a task finishes, unfortunately the postback only fires at the end of an event (the listbox only updates right at the end). I need an interactive update as a task finishes, not sure if this is possible.

    Some demo coding

    ListBox1.Items.Add("Finished the first item"
    Threading.Thread.Sleep(1000)'This is only for 'demonstration, would be executing an sql statement 'or similar task
    ListBox1.Items.Add("Finished the second item"
    Threading.Thread.Sleep(1000)
    ListBox1.Items.Add("Finished the third item"
    Threading.Thread.Sleep(1000)
    End Sub 'All three items are only refreshed or 'posted back here

    להגיב