Microsoft.NET

……………………………………………….Expertise in .NET Technologies

Asynchronous Pages in ASP.NET 2.0 – Page Model Part IV

Posted by Ravi Varma Thumati on October 5, 2009

Many contention problems in ASP.NET are caused by latency of external calls (such as Web service or database calls), file IO latency, etc. When a request is made against an ASP.NET application, ASP.NET uses one of its worker threads to service that request. That request owns that thread until the request is complete and the response has been sent. ASP.NET 2.0 seeks to resolve latency issues with these types of issues by adding the capability to execute pages asynchronously. That means that a worker thread can start the request and then hand off additional execution to another thread, thereby returning to the available thread pool quickly. When the file IO, database call, etc. has completed, a new thread is obtained from the thread pool to finish the request.

The first step in making a page execute asynchronously is to set the Async attribute of the page directive like so:

<%@ Page Async="true" %>

This attribute tells ASP.NET to implement the IHttpAsyncHandler for the page.

The next step is to call the AddOnPreRenderCompleteAsync method at a point in the lifecycle of the page prior to PreRender. (This method is typically called in Page_Load.) The AddOnPreRenderCompleteAsync method takes two parameters; a BeginEventHandler and an EndEventHandler. The BeginEventHandler returns an IAsyncResult which is then passed as a parameter to the EndEventHandler. 

Note: An async page does not render to the browser until the EndEventHandler has completed. No doubt but that some developers will think of async requests as being similar to async callbacks. It’s important to realize that they are not. The benefit to asynchronous requests is that the first worker thread can be returned to the thread pool to service new requests, thereby reducing contention due to being IO bound, etc.

Script Callbacks in ASP.NET 2.0

Web developers have always looked for ways to prevent the flickering associated with a callback. In ASP.NET 1.x, SmartNavigation was the most common method for avoiding flickering, but SmartNavigation caused problems for some developers because of the complexity of its implementation on the client.  ASP.NET 2.0 addresses this issue with script callbacks. Script callbacks utilize XMLHttp to make requests against the Web server via JavaScript. The XMLHttp request returns XML data that can then be manipulated via the browser’s DOM. XMLHttp code is hidden from the user by the new WebResource.axd handler.

There are several steps that are necessary in order to configure a script callback in ASP.NET 2.0.

Step 1 : Implement the ICallbackEventHandler Interface

In order for ASP.NET to recognize your page as participating in a script callback, you must implement the ICallbackEventHandler interface. You can do this in your code-behind file like so:

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

You can also do this using the @ Implements directive like so:

<%@ Implements Interface="System.Web.UI.ICallbackEventHandler" %>

You would typically use the @ Implements directive when using inline ASP.NET code.

Step 2 : Call GetCallbackEventReference

As mentioned previously, the XMLHttp call is encapsulated in the WebResource.axd handler. When your page is rendered, ASP.NET will add a call to WebForm_DoCallback, a client script that is provided by WebResource.axd. The WebForm_DoCallback function replaces the __doPostBack function for a callback. Remember that __doPostBack programmatically submits the form on the page. In a callback scenario, you want to prevent a postback, so __doPostBack will not suffice.

Note: __doPostBack is still rendered to the page in a client script callback scenario. However, it’s not used for the callback.

The arguments for the WebForm_DoCallback client-side function are provided via the server-side function GetCallbackEventReference which would normally be called in Page_Load. A typical call to GetCallbackEventReference might look like this:

// Set up the JavaScript callback string cbRef = cm.GetCallbackEventReference(this, "document.getElementById('ddlCompany').value", "ShowCompanyName", "null", true);

Note: In this case, cm is an instance of ClientScriptManager. The ClientScriptManager class will be covered later in this module.

There are several overloaded versions of GetCallbackEventReference. In this case, the arguments are as follows:

this

A reference to the control where GetCallbackEventReference is being called. In this case, it’s the page itself.

document.getElementById('ddlCompany').value

A string argument that will be passed from the client-side code to the server-side event. In this case, Im passing the value of a dropdown called ddlCompany.

ShowCompanyName

The name of the client-side function that will accept the return value (as string) from the server-side callback event. This function will only be called when the server-side callback is successful. Therefore, for the sake of robustness, it is generally recommended to use the overloaded version of GetCallbackEventReference that takes an additional string argument specifying the name of a client-side function to execute in the event of an error.

null

A string representing a client-side function that it initiated before the callback to the server. In this case, there is no such script, so the argument is null.

true

A Boolean specifying whether or not to conduct the callback asynchronously.

The call to WebForm_DoCallback on the client will pass these arguments. Therefore, when this page is rendered on the client, that code will look like so:

WebForm_DoCallback('__Page',document.getElementById('ddlCompany').value, ShowCompanyName,null,null,true)

Notice that the signature of the function on the client is a bit different. The client-side function passes 5 strings and a Boolean. The additional string (which is null in the above example) contains the client-side function that will handle any errors from the server-side callback.

Step 3 : Hook the Client-Side Control Event

Notice that the return value of GetCallbackEventReference above was assigned to a string variable. That string is used to hook a client-side event for the control that initiates the callback. In this example, the callback is initiated by a dropdown on the page, so I want to hook the OnChange event.

To hook the client-side event, simply add a handler to the client-side markup as follows:

// Hook the JavaScript function to the onchange event of the dropdown ddlCompany.Attributes["onchange"] = String.Format("javascript:{0}", cbRef);

Recall that cbRef is the return value from the call to GetCallbackEventReference. It contains the call to WebForm_DoCallback that was shown above.

Step 4 : Register the Client-Side Script

Recall that the call to GetCallbackEventReference specified that a client-side script called ShowCompanyName would be executed when the server-side callback succeeds. That script needs to be added to the page using a ClientScriptManager instance. (The ClientScriptManager class will be dicussed later in this module.) You do that like so:

System.Text.StringBuilder clientScript = new System.Text.StringBuilder(""); ClientScriptManager cm = Page.ClientScript; // Create the client script clientScript.Append("function ShowCompanyName(companyName)"); clientScript.Append("{"); clientScript.Append("document.getElementById('CoClicked').innerHTML = \"You chose \" + companyName + \".\";"); clientScript.Append("}"); cm.RegisterClientScriptBlock(this.GetType(), "showCo", clientScript.ToString(), true);

Step 5 : Call the Methods of the ICallbackEventHandler Interface

The ICallbackEventHandler contains two methods that you need to implement in your code. They are RaiseCallbackEvent and GetCallbackEvent.

RaiseCallbackEvent takes a string as an argument and returns nothing. The string argument is passed from the client-side call to WebForm_DoCallback. In this case, that value is the value attribute of the dropdown called ddlCompany. Your server-side code should be placed in the RaiseCallbackEvent method. For example, if your callback is making a WebRequest against an external resource, that code should be placed in RaiseCallbackEvent.

GetCallbackEvent is responsible for processing the return of the callback to the client. It takes no arguments and returns a string. The string that it returns will be passed as an argument to the client-side function, in this case ShowCompanyName.

Once you have completed the above steps, you are ready to perform a script callback in ASP.NET 2.0.

Script callbacks in ASP.NET are supported in any browser that supports making XMLHttp calls. That includes all of the modern browsers in use today. Internet Explorer uses the XMLHttp ActiveX object while other modern browsers (including the upcoming IE 7) use an intrinsic XMLHttp object. To programmatically determine if a browser supports callbacks, you can use the Request.Browser.SupportCallback property. This property will return true if the requesting client supports script callbacks.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: