devxlogo

Whidbey Simplifies Browser Client Script Callbacks

Whidbey Simplifies Browser Client Script Callbacks

here are plenty of good reasons to anticipate Whidbey, among which are a number of enhancements for client script support, including new attributes and a ClientScriptManager class to handle client scripts. However, perhaps the most welcome client-script enhancement feature is Whidbey’s support for remote server callbacks using client script.

Refreshing or posting a page to do a data lookup is an extremely common technique. In classic ASP, developers used script to handle submitted data, which often made ASP code very difficult to maintain. Like most multi-page Web applications, posting form data to the server caused a complete request-response cycle, where the server would respond to the post with an entirely new page. The browser, naturally, would then render the new page in place of the existing page. This constant page-redrawing tends to make the user experience awkward and slow. One way that developers alleviated such interface problems was by using remote scripting, which used Java applets to make server calls in combination with DHTML’s dynamic rendering to display updated or new data on an existing page. Alternatively, for pure-IE applications, developers could use client-side script with the XMLHttpRequest object to make background data requests. But both methods required non-trivial efforts, and debugging, in particular, was difficult.

Developers looked forward to some relief in the initial ASP.NET release?and they got some. Server controls, ViewState, automated postback, and the event-based ASP.NET model solved a lot of problems, and SmartNavigation (in IE-only applications) helped as well. But for cross-platform applications, developers continued to rely on remote scripting. In ASP.NET v2.0 (Whidbey), that has changed.

Whidbey’s Client Callback Support

Figure 1. Flow of Callback: You can follow the route of the callback as it is handled by both server and client.

In Whidbey, clients can call a server method, pass data, and get results without posting a form. These calls use the XMLHTTP object in the background to make requests to the server, but you have to write much less special code to handle the calls.

Figure 1 shows the flow for the application logic. You write a client function (Step 2) to make a call to the server, and set up a custom server event (Step 1c) to handle this call. CallBackManager is an intermediary that handles steps 3 through 6, which includes the routing of the call from client to the server and pushing back the data from server to client. Another client function (Step 7) handles the response. Effectively, you write two client-side functions to make a request and handle the response.

To better explain how it works, here’s how to set up a sample implementation of the callbacks.

Figure 2. E-R Diagram: You can see the tables you need for the sample application and their relationship to one another.

Implementing a Lookup
Assume you have a page that needs to fetch data from three tables: Region, Country, and City (see Figure 2).

This is a typical example of the “dependent list” problem. When a user selects a region the application should fill the Country list with countries from that region. Similarly, when the user selects a country, the City list should contain only relevant cities for the selected country. In other words, it’s a hierarchy in which each list’s contents depends entirely on the user’s selection from its “parent” list (see Figure 2).

It’s certainly possible to implement this scenario using the normal postback technique, but you’d have to put up with the slow performance of a complete page redraw for each request. Instead, you can provide a better, faster user experience using remote callbacks, because you can maintain all the page layout code, sending only relevant arguments and receiving only the relevant data.

Download the sample application that accompanies this article. The included callback.sql script configures a SQL Server or MSDE database with the data. Run that script first (you may need to alter the script for other databases). Then begin your implementation by starting up Visual Studio.NET Whidbey.

To create your project, select the template type “ASP.NET Web Site” (see Figure 3). This creates a page named default.aspx; rename it, if desired.

Making Client Callbacks
You can now use this function from the client end to call back to the server, passing the relevant arg and ctx parameter values. However, you should also consider the changes in the RegisterClientScriptBlock declaration that occurred between ASP.NET versions 1 and 2. In ASP.NET v2.0 you can use the ClientScriptManager object associated with the page to register the script block. The Page.property ClientScript returns this ClientScriptManager object. You have two overloaded methods to choose from for registering scripts; here’s the one I chose for this example:
   public void RegisterClientScriptBlock(      Type type, string key,                                 string script, bool addScriptTags)

Table 2 shows the meaning of the parameters to this call.

Table 2. Parameter description for RegisterClientScriptBlock method.

Arguments

Description

Type

RegisterStartUpScript and RegisterClientScriptBlock can now takethe same key name without problems because of this parameter.

This.GetType() is used in the sample

Key

Unique value for the script block.

“CallServer” is the key value used.

Script

The actual script block to emit.

In this sample the StringBuilder provides this value.

addScriptTags

A bool value.

True?This would enclose the script within the “

The last thing you want to do during the page load event is to fetch the dropdown data for the region so that the user will be able to make an immediate selection from the list. When the page loads only the region dropdown list will be populated.

The next step is to pass the selected region. from the client to the server and return the processed values. The code blocks in the page load event have already added the onchange attributes for the dropdown list as follows:

   cboRegion.Attributes.Add("onchange",       "SelectRegion();");   cboCountry.Attributes.Add("onchange",       "SelectCountry();");

Listing 2 shows the implementation of the SelectRegion function.

The JavaScript function in Listing 2 clears values (if any) in the country and city dropdown list controls. It then calls the CallServer (registered in Page_Load) method to pass the region and the context parameters.

The region parameter value is a combination of Country + delimiter + the selected region value, e.g. “Country?1, where the delimiter (the square) is a non-editable (unkeyable) character (String.FromCharCode(20)). The application generates the delimiter programmatically to ensure that the delimiting is foolproof.

The second parameter (context) is the identifier of the country dropdown list. (I will explain the reasoning behind the use of the delimiters and the context parameter later in this article.) If you recall, the server-side RaiseCallbackEvent implementation is still pending. Copy the code snippet in Listing 3 into the RaiseCallbackEvent event declaration, making sure to read the comment code.

The eventArgument parameter provides the handle to the region value from the client, e.g. “Country?1”. You split this into a string array using the Char.ConvertFromUtf32(20) method. The first array element will be “Country” and the second “1”. You then use a switch statement to make a correct data fetch, in this case for countries matching the region ID “1”. As you can see, you have to append a delimiter to distinguish the event calls to fetch either countries or cities. Again you would append the values in “CountryId” + “ColumnDelimiter” + “CountryName” + “RowDelimiter” format. (You could accomplish this just as easily using XML.).

The resulting string value is a string of delimited values similar to: “1?India?2?China?3?Japan?4?Srilanka”.

Handling Callbacks
Now you need to add two client methods to handle callbacks: a CallBackHandler method to handle successful callbacks, and an ErrorCallBack method to handle any errors. Listing 4 shows the script definitions. Note that both methods have similar signatures.

The CallBackHandler method’s result parameter will be the list of delimited strings returned from the RaiseCallbackEvent, and the value of the context parameter will be the appropriate control id (the same as the CallServer method’s second parameter?remember, you’re passed the “id” of the country control as a context parameter in Listing 2). Note that the if(context == “cboCountry”)… statement uses the context to get the reference to the appropriate form element. With that information in hand, all that remains is to handle the return value, using split to obtain an array with which you populate the appropriate dropdown list.

Error Handling
Whenever a server-side error occurs during remote calls the CallBackManager routes the callback to the ErrorCallBack method. Listing 1 shows how it assigns the ErrorCallBack. The ErrorCallBack method included in the sample code just displays a client-side alert message, but you should include more appropriate error-handling in deployed applications. The result parameter value provides the actual error message. To test this, throw some exception from the server-side event, and then check the value.

You’re ready to run the sample and see the callback work. If you opt to run the enclosed sample, extract the files to a folder and open this folder as your Web site. Be sure to check and update the connectionstring value in the Web.config file before you run the project.

Author’s Note: Not all browsers support the callback implementation. To find this, use the class HttpBrowserCapabilities and check the return values of the two new bool properties: SupportsCallback and SupportsXmlHttp. A return value of True means the browser supports the callback implementation.

The callback capability in ASP.NET v2.0 is a far better implementation model than remote scripting. You can implement callbacks to retrieve lookup data, invoke backend events, or validate user input values. Callbacks can improve performance by fetching only relevant data asynchronously. Using XML can make your callbacks even more powerful. You can use the support for error callbacks very effectively to validate user input. But the biggest advantage?by far?is freeing your end users from the unpleasantness of the full-page postback/redraw cycle.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist