Infosys Microsoft Alliance and Solutions blog

« Settings in .net Fwk 2.0 | Main | BizTalk 2006 - 2004 Performance Comparison »

Enhanced Client Side Functionalities in ASP.NET 2.0,,,

We have seen the significance of utilizing worker threads in user interface applications wherein responsiveness to the end user is of paramount importance. Proper usage of asynchronous pattern will yield not only better responsiveness but also better performance as well as scalability, since system’s critical resources such as threading are to be better utilized. However, a word of caution is, poor usage of threading might invariably lead to unpredictable (or highly predictable Smile)  nightmare.

Both desktop and browser based applications would require asynchronous mechanism in order not to force the end users to stare philosophically at the blank (or filled with little incoherent content) screens too often and too long.  While lack of any sort of responsiveness (or absence of any visible action) is a critical problem to both types of applications, sometimes, too much of responsiveness (or frequent dynamism) might also prove to be a nagging issue, specifically in web client applications. To be precise, I just mean frequently visible UI changes by the words “too much of responsiveness”.

The server centric web applications such as ASP.NET applications, based on its inherent request/response model and postback mechanism will have a bunch of pages that will be posted back to the server multiple times to carry out a business task.

The problems associated with this model are

i.  Large amount of data is transmitted across wire, multiple times, unnecessarily. The famous postback mechanism transmits the data (all user inputs as well as the hidden viewstate data) to the server for processing. For example, if an employee id is all that is required to pull off the details about him/her from the server side, employee id is not just one input that flows into the server side, in this model.

ii.  Server needs to do a lot of processing, time and again, for creating the content of whole page, by undergoing the ritualistic process of page building (remember HttpRuntime, Handlers, modules, page object etc).

iii.  Rendering the whole page content for just to update its small portion will have unwarranted flickering effect on the user interface.

In the cases of high amount of performance and scalability requirements, first two points should pose a challenge and would get the attention from design and development team. Despite the fact that gauging how much pesky the issue that is related to third point is bit difficult ( as it depends on the characteristics of people that application is catering to Smile), this issue, in general, continues to be a point of frustration for web application developers and a point of irritation for seasoned web users.

So, how to tackle these problems that are offshoot of server centric, browser based web applications? Again asynchronous programming comes into picture to handle such issues. But, something more other than asynchronous mechanism is needed to tackle them. Enhanced client side functionalities in ASP.NET 2.0 are that something more.

What all required to handle these issues are that external server side call/a web request should be made from client side and server should respond to the client script by not discarding the content of the current page. Then a callback method from client side should be able to update a part of the page’s content through DHTML object model. It means that we do not try to eliminate the round trip to the server completely. But we try to eliminate transmitting unnecessarily large amount of data. Instead of a server control postbacks the web request; here a client side control tries to do that. But this request is of completely different type – callback request rather than to be a normal postback request. ASP.NET runtime understands this distinction so it will not do the significant task, of refresh the the page content completely as it generally does in normal requests. This fact is so important for eliminating the flickering effect or achieving the partial-rendering of the page. If I rephrase it correctly, this fact is so important for achieving the partial partial-rendering of the page Smile. Partial rendering of the page gets fully completed when server side sends the response of the callback page request to the client side script that updates the specific portion of the page by using DHTML object model.

I have developed a sample web page that executes a web service call and updates the result without causing the page to flicker through the usage of script callback mechanism.

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Text;
public partial class _Default : System.Web.UI.Page, ICallbackEventHandler 
{
    string resultStr = string.Empty;
   
    protected void Page_Load(object sender, EventArgs e)
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine();
        sb.Append("<script language=\"javascript\">");
        sb.AppendLine();
        sb.Append("function clientCallbackMethod(arg, context)");
        sb.AppendLine();
        sb.Append("{");
        sb.AppendLine();
        sb.Append("document.all['textAreaBio'].value = arg;");
        sb.AppendLine();
        sb.Append("}");
        sb.AppendLine();
        sb.Append("</script>");
        sb.AppendLine();

        
        ClientScriptManager csm = this.ClientScript;
        csm.RegisterClientScriptBlock(typeof(string), "MyScript", sb.ToString());
        string strCallbackScript = csm.GetCallbackEventReference(this, "document.all['textBoxName'].value", "clientCallbackMethod", null, true);
        StringBuilder sbTextBox = new StringBuilder();      
        sbTextBox.Append("<input id=\"textBoxName\" type=\"text\" runat=\"server\" style=\"width: 207px\" />" );
        csm.RegisterClientScriptBlock(typeof(HtmlInputText), "MyHtmlText", sbTextBox.ToString());
        StringBuilder sbClickButton = new StringBuilder();
        sbClickButton.AppendFormat("<input id=\"btnForTextBoxName\" type=\"button\" value=\"Click!!!\" runat=\"server\" onClick=\"javascript:{0}\" />", strCallbackScript);
        csm.RegisterClientScriptBlock(typeof(HtmlButton), "MyClickButton", sbClickButton.ToString());
        StringBuilder sbTextArea = new StringBuilder();
        sbTextArea.Append("<br/><textarea id=\"textAreaBio\"  visible=\"false\" style=\"width: 208px; height: 80px\" ></textarea>" );
        csm.RegisterClientScriptBlock(typeof(HtmlButton), "MyHTMLButton", sbTextArea.ToString());
         
       
    }
    public virtual void RaiseCallbackEvent(string eventArgs)
    {
        SayHelloWebService.Service proxy = new SayHelloWebService.Service();       
        resultStr = proxy.GetBio(eventArgs);
    }
    public virtual string GetCallbackResult()
    {
        return resultStr;       
    }
   
}

Conceptually, an end user will initiate a call to server by activating certain event of an UI control in the web page. That triggered event should invoke a call to external server (in this sample, I do use local web service). Having processed that call, the server would return the result by calling back the client side method. Then the client side method should update the specific portion of the page. Overall, this task requires some action in both server and client side. If you think that we have to do all the plumbing that is required to achieve this task, fortunately it is not so. But, understanding of the plumbing work that is done automatically by .NET Fwk  is very essential to appreciate the flexibility of .NET Fwk 2.0 as well as Atlas.

You would have noticed that I have implemented “ICallbackEventHandler” along with default “System.Web.UI.Page” class, in this page.  This interface consists of two methods, RaiseCallbackEvent and GetCallbackResult that need to be implemented by us to execute some server side coding and get back the result. Now, these pieces, should be somewhat plumbed with client side scripting, as we would like to invoke server side calls in out of band way, so that result of this calls should not end up in refreshing the current page.

The key players in this code are methods of “ICallbackEventHandler” (“RaiseCallbackEvent” and “GetCallbackResult”), “GetCallbackEventReference” and “RegisterClientScriptBlock”.

RegisterClientScriptBlock” method allows us to create the client script from within server side and register them for the page. In this sample, I have created three client script pieces that are nothing but the html code to create three HTML UI controls such as text box, button and text area. In fact, you can create them in Default.aspx page by dragging and dropping the html controls from tool box. But I did not want to clutter that design page as I wanted you to know how lot of extra coding is generated, consequently as the result of usage of the above mentioned methods. So, those are plain HTML controls, and clicking of the button after inputting a name into Html text box control, would show the biography content in another HTML control, text area.

when I click “Click!!!” button, that I have to get the input from text box control and pass that as a parameter to my web service call which supplies back the biography content. So, plumbing needs to be done between client side button event to server side web service call.

That plumbing is done through GetCallbackEventReference method. This method creates client side event handler code, by taking couple of parameters that provide information such as who implements the ICallbackEventHandler, what is the input value, what client side method is to be executed after a server side operation is completed, context to be passed, and whether this method will be invoked in asynchronous manner. See the following code snippet.

string strCallbackScript = csm.GetCallbackEventReference(this, "document.all['textBoxName'].value", "clientCallbackMethod", null, true);

GetCallbackEventReference method will create the following piece of code (that you will see when you click on the view source option of context menu of the rendered web page) as a string.

WebForm_DoCallback('__Page',document.all['textBoxName'].value,clientCallbackMethod,null,null,true)

This method, in fact performs the magic of sending out of band web request to the server from client side and that request, when it gets processed by the ASP.NET runtime,  in turn, will invoke “RaiseCallbackMethod()” of current Page, as this is the one that implemented “ICallbackEventHandler”. “RaiseCallbackMethod()” will invoke the web service call, as given below.

public virtual void RaiseCallbackEvent(string eventArgs)
{
SayHelloWebService.Service proxy = new SayHelloWebService.Service();       
resultStr = proxy.GetBio(eventArgs);
}

If you are bit perplexed about how this WebForm_DoCallback() method has been wired with html button’s click event, See the code given below.

StringBuilder sbClickButton = new StringBuilder();
sbClickButton.AppendFormat("<input id=\"btnForTextBoxName\" type=\"button\" value=\"Click!!!\" runat=\"server\" onClick=\"javascript:{0}\" />", strCallbackScript);
csm.RegisterClientScriptBlock(typeof(HtmlButton), "MyClickButton", sbClickButton.ToString());

Once the web service call is completed, “GetCallbackResult()” returns the result to the client side javascript method “clientCallbackMethod()” that I created and registered from server side. By clicking on the “View Source” option of web page’s context menu (by right clicking), you can see the script that I had registered.

<script language="javascript">

function clientCallbackMethod(arg, context)

{

document.all['textAreaBio'].value = arg;

}

</script>

Having received the result through its parameter “args”, “clientCallbackMethod()” updates the value in the text area control.

When most of the  pieces are falling into their places, one may still wonder what that WebForm_DoCallback() really does in the back ground. Well, it is not acting all alone.  I have given below the complete script created by the page, so that you can see various bits and pieces that are required but created automatically by the page. I have deleted some lines of script and realigned some, for clarity. But you can see the complete script through View Source option in the context menu of the rendered page.

<form name="form1" method="post" action="Default.aspx" id="form1">

<div>

<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />

<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUJNzgzNDMwNTMzZGS0ExybgjnKXUzuLL5XZJnfITsM5A==" />

</div>

 

<script type="text/javascript">

<!--

var theForm = document.forms['form1'];

if (!theForm) {

    theForm = document.form1;

}

function __doPostBack(eventTarget, eventArgument) {

    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {

        theForm.__EVENTTARGET.value = eventTarget;

        theForm.__EVENTARGUMENT.value = eventArgument;

        theForm.submit();

    }

}

// -->

</script>

<script src="/MyScriptCallbackWebSite/WebResource.axd?d=70lWo11C5EZPx_FfFXIoVg2&amp;t=632964141447332273" type="text/javascript"></script>

<script language="javascript">

function clientCallbackMethod(arg, context)

{

document.all['textAreaBio'].value = arg;

}

</script>

<input id="textBoxName" type="text" runat="server" style="width: 207px" />

<input id="btnForTextBoxName" type="button" value="Click!!!" runat="server" onClick="javascript:WebForm_DoCallback('__Page',document.all['textBoxName'].value,clientCallbackMethod,null,null,true)" />

<br/>

<textarea id="textAreaBio"  visible="false" style="width: 208px; height: 80px" ></textarea>   

<script type="text/javascript">

<!--

WebForm_InitCallback();// -->

</script>

</form>

Don’t worry too much, if much of the content makes no sense, now. In fact, there is no need for us to know all these nitty-gritty. The fact is WebForm_DoCallback() method does the crucial work of sending an out of band web request to the server. When it does that, it includes lot of information in the request so that ASP.NET runtime would understand that this call is completely different from normal web requests and what to do further on this request. Then Http Handler will handle this request appropriately by invoking “RaiseCallbackEvent()” method, in the server side. The completion of this method will trigger the client side callback method “clientCallbackMethod()” and that would update the content in text area html control.

By this time you would have suspected the hands of XMLHTTP object which are somewhere hidden in this scene. Yes, WebForm_DoCallback() internally uses the XMLHTTP object and send the request to the server. ASP.NET provides a new spin to the whole story by abstracting the usage of XMLHTTP object and by hiding the tediousness associated with creating lot of plumbing  javascript from the scratch.

For more internal details on it, please go through the excellent article in the link, http://msdn.microsoft.com/msdnmag/issues/04/08/CuttingEdge/

This approach using script callback mechanism eliminates the list of problems that I stated earlier as

i.  only small amount of data is passed to the server side comparing to normal web request

ii.  ASP.NET runtime also short-circuits the http handler mechanism to handle this specific callback request differently from normal postback based page requests

iii. it makes the partial rendering of a page, possible.

But story does not end here. ASP.NET 2.0 AJAX extensions, earlier code named Atlas, provide more flexibility in terms of creating visually appealing applications with less scripts to be crafted manually. An important thing to be noted down here is Atlas is not just a bunch of client side script code. It really steroids javascript through JSON (Javascript object notation) and provides a set of new controls and components (for both client and server side) with an AJAX script library that comprises the common development tasks. For example, Atlas would simplify the given code further as it supplies the control to call web services directly from client side code.  

TrackBack

TrackBack URL for this entry:
http://infosysblogs.com/microsoft-mt/mt-tb.fcgi/34

Comments

Ganesan, Webservice behavior as a feature has been available for a long time. Atlas/AJAX looks like old wine in new bottle ! Why do you think this didn't get much popular earlier and why should Atlas/AJAX be much better?

Atul, I have started posting a blog series on ASP.NET 2.0 AJAX Extensions (earlier codenamed as Atlas). I will explain the power and flexibility of Atlas in those blogs.

Thanks Ganesan

Atlas is nothing new fundamentally, AJAX .Net already provided a similar functionality a long time ago. Additionally has good JSON integration.

Great,
Iam a beginner to asp.net,
can you please send me the sample code so as to understand better.

expecting your valuable reply.

regards,
Thirumurugan.

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)