Skip navigation

Remote Web Operations the <st1:Street><st1:address>AJAX Way</st1:address></st1:Street>

Ping an IP Address and Refresh the User Interface

CoreCoder

LANGUAGES: C#

ASP.NET VERSIONS: 2.0 | 3.5 Beta 2

 

Remote Web Operations the AJAX Way

Ping an IP Address and Refresh the User Interface

 

By Dino Esposito

 

As emphatic as it may seem, AJAX enables developers to successfully face scenarios that were difficult to deal with using the ordinary tools of classic Web programming. Flicker-free page updates is the canonical example of the benefits brought by AJAX, but have you ever considered making asynchronous calls to remote IP addresses? Using the power of AJAX, you can trigger a call to a URL and report to the client, merged in the user interface, any response you get from it. Nicely enough, all this can happen regardless of the time it may take to complete the call and even regardless of what the user is doing on and with the current page.

 

AJAX provides the tools to implement remote method calls or simply ping an IP address. However, as usual, the devil is in the details; as you ll read in this column, there are many more aspects to consider than one may think at first.

 

As an example, let s consider tools and techniques to call a remote method in ASP.NET AJAX Extensions 1.0 with and without the user s intervention. I ll first explain how to expose some remote piece of code to a JavaScript-enabled client browser, then I ll illustrate how to invoke it explicitly (such as clicking a button) and implicitly (using a timer, for example). Both code and techniques are guaranteed to work with ASP.NET AJAX Extensions version 1.0. They also work with Beta 2 of ASP.NET 3.5.

 

Define a Script-callable Remote Method

In an AJAX scenario, you can only use the JavaScript engine of the browser to execute actions. For security reasons, though, all browsers tend to sandbox most of the things one might want to do to make Web pages cooler and more powerful. In this context, the key restriction is that you can t invoke IP addresses and URLs located outside the domain of the current application. Put another way, with most AJAX frameworks and certainly with ASP.NET AJAX Extensions you can t simply target any URLs you want from the client browser. You can t bind to, say, the Amazon Web service or ping an arbitrary network address. You can do this only if the target URL lives within the domain of the page making the call.

 

Does this mean that all the wonderful things you ve heard about AJAX are just hype? Not exactly. There s a simple and effective workaround to the built-in browser sandbox for script code you just don t use the browser to trigger the call. The sandbox, therefore, applies to the JavaScript engine within the browser, but it neither affects nor limits what you can code on the server side of your application. So the idea is, you bind your JavaScript event handlers to a script-callable service defined in your Web application. Next, your server-side code (typically a made-to-measure Web service or a WCF service in ASP.NET 3.5) will be free to place calls to any IP address in the global network of the Internet.

 

So, what s a script-callable service? Such a generic description identifies a piece of server-side and largely platform-independent code that accepts calls from a client browser. Each AJAX framework may have its own definition of a script-callable service. As far as ASP.NET AJAX Extensions is concerned, a script-callable service is a plain ASP.NET Web service decorated with a special attribute and backed up by a made-to-measure HTTP handler for ASMX resources. You plug the ad hoc HTTP handler in the runtime of the application using the <httpHandlers> section of the web.config file:

 

<httpHandlers>

 <remove verb="*" path="*.asmx"/>

 <add verb="*"

    path="*.asmx"

    validate="false"

    type="System.Web.Script.Services.ScriptHandlerFactory,

      System.Web.Extensions, ... />

 :

</httpHandlers>

 

The preceding script is automatically inserted in the web.config file that both Visual Studio 2005 and Visual Studio 2008 generate when an AJAX Web site is created. In addition to servicing classic and SOAP-based Web service calls, the new ASMX handler also accepts calls coming from AJAX clients. What s the difference between AJAX calls and classic Web service calls? An AJAX call carries JSON data instead of SOAP, and brings a special signature in the content-type request header. The AJAX-enabled ASP.NET runtime recognizes AJAX calls and packs the response in a JSON stream instead of a SOAP packet. Figure 1 shows a sample Web service that can be invoked from within AJAX pages.

 

namespace Samples

{

  [ScriptService]

 public class TimeService : System.Web.Services.WebService

 {

     public TimeService() {}

      [WebMethod]

     public string GetTimeFormat(string format)

     {

         return DateTime.Now.ToString(format);

     }

 }

}

Figure 1: A sample script-callable Web service.

 

At first glance, the code in Figure 1 is in no way different from that of a regular ASP.NET Web service that exchanges SOAP packets with clients. Take a closer look, though, and you ll notice the ScriptService attribute. That s the key attribute that instructs the AJAX-enabled ASP.NET runtime to accept and service JSON requests directed at the service s URL.

 

Bind a Script Service

The next step is enabling a Web page to call into the methods of the service via JavaScript. In ASP.NET AJAX, this requires that you register the service with the page s script manager control. By the way, all ASP.NET AJAX pages require exactly one instance of the ScriptManager control, as shown here:

 

<asp:ScriptManager ID="ScriptManager1" runat="server">

 <Services>

    <asp:ServiceReference Path="~/WebServices/

     TimeService.asmx" />

 </Services>

</asp:ScriptManager>

 

When the ScriptManager control is called to render its own markup, it expands any child ServiceReference tag to a <script> tag and makes it point to the same ASMX URL with a /js suffix. This trick guarantees that the client browser transparently downloads a proxy script class for your JavaScript handlers to call into. Let s suppose you have a page with a button. By clicking the button, the user triggers a call to the AJAX Web service (Figure 2 shows a sample Web page that does this).

 

<script language="javascript" type="text/javascript">

 function getCurrentTime()

 {

     Samples.TimeService.GetTimeFormat(

      "ddd, dd MMMM yyyy [hh:mm:ss]", onMethodCompleted);

 }

 function onMethodCompleted(results)

 {

     $get("Label1").innerHTML = results;

 }

</script>

<html>

<body>

 <form runat="server">

    

What time is it on the server?

    <input type="button" value="Get Time"

      onclick="getCurrentTime()" />

    <hr />

    <asp:Label runat="server" ID="Label1" />

 </form>

</body>

</html>

Figure 2: Calling an AJAX service.

 

Let s take a closer look at the getCurrentTime JavaScript function. It calls into a built-in Samples.TimeService class. Where does this class originate? That s precisely the service proxy class the ScriptManager control linked to the page. The class mirrors the public programming interface of the Web service and uses classes in the Microsoft AJAX Client Library (a native part of the ASP.NET AJAX Extensions framework) to execute remote HTTP calls. As a page developer, you don t have to worry about linking the AJAX Client library; that s simply yet another task the script manager silently handles.

 

The prototype of the methods defined on the service proxy class features a few extra arguments than the corresponding methods on the Web service. If you look back at Figure 2, in fact, you see an additional onMethodCompleted argument in the call to the GetTimeFormat method. Method calls execute asynchronously, meaning that a callback function is required to sync up the page when the response of the method is ready. The complete signature of a service method is shown here:

 

function GetTimeFormat(params,

   onMethodCompleted,

   onMethodFailed,

   userContext)

 

The regular list of method arguments is followed by up to three parameters: a success callback, a failure callback, and a user context object. These parameters are optional, but the success callback is virtually mandatory if you want to refresh the user interface or perform any action following the method call. The failure callback is invoked if any unhandled exception is raised during the Web service method execution. The user context object is any JavaScript object you want to pass down the way to success and failure callbacks. You use the context object to come up with more modular code and to avoid global variables when information sharing is needed between the main page flow and the callbacks. The complete signature of the callback is shown here:

 

function onMethodCompleted(results, userContext, methodName)

 

The first argument indicates the return value from the method. In case of failure, the argument represents an instance of a JavaScript system class that describes the trapped exception. The second argument is the same user context object that you may have optionally specified in the call. Finally, the third argument is a string that stores the name of the service method just called.

 

Automatic Calls

The model hitherto described works great when the remote call should execute following a specific user request, such as a click, a keystroke, or perhaps a mouse movement. What if, instead, you need to call the method periodically, at specific times, or upon page loading?

 

To schedule a JavaScript action at a given relative or absolute time, you must rely on client timers. A client timer is created by the setTimeout method on the window object. The window object is part of the browser s object model (BOM) and represents the browser s current window. By calling the setTimeout method, you instruct the browser to wait for the specified amount of time and then execute a given piece of script code. The setTimeout method returns a reference to the timer object that you ll store to be able to stop and destroy the timer later. This code snippet shows how to define a timer that invokes the functionToCall JavaScript callback function after 10 seconds:

 

var _timer = window.setTimeout(

   "functionToCall", 10000);

 

By recreating the timer in the callback, you can periodically invoke the same piece of code, thus pinging a remote URL for whatever reason you need.

 

If you simply need to make an asynchronous method call upon page loading, you can add a special JavaScript event handler to your ASP.NET AJAX page, as shown here:

 

function pageLoad()

{

  :

}

 

The function must be named pageLoad; it executes as soon as the Microsoft AJAX Client Library has been fully loaded and initialized. This event handler represents the safest way to execute AJAX script code upon the loading of an ASP.NET page.

 

Timers and Partial Rendering

The ASP.NET AJAX toolbox also contains a server-side Timer control (basically the server-side version of a JavaScript timer), which injects script code that creates and consumes an ad hoc timer on the client. The server-side Timer control posts back each time the interval expires. The Timer control is particularly helpful in ASP.NET AJAX pages that use partial rendering. Partial rendering partitions the page in regions of markup that can be refreshed individually and independently from others. This means you can refresh only a portion of the page, leaving the rest intact. By associating an updatable region with a timer, you can have that region refresh periodically. For example, suppose you want to implement a digital clock. It basically consists of a region of markup with a label. An updatable region is defined as the content of a new control named UpdatePanel. Figure 3 shows the full source code you need.

 

<asp:ScriptManager runat="server" ID="ScriptManager1" />

<asp:UpdatePanel runat="server" ID="UpdatePanel1">

   <ContentTemplate>

      <asp:Label runat="server" ID="Label1" />

   </ContentTemplate>

   <Triggers>

      <asp:AsyncPostBackTrigger ControlID="Timer1"

        EventName="Tick" />

   </Triggers>

</asp:UpdatePanel>

<asp:Timer ID="Timer1" runat="server" OnTick="Timer1_Tick"

 Interval="1000" />

Figure 3: An automatically refreshing page region.

 

The updatable region is refreshed whenever the associated trigger (the timer) is fired. The timer posts back from the client whenever the interval expires. The postback event fired on the server is the Tick event:

 

protected void Timer1_Tick(object sender, EventArgs e)

{

   Label1.Text = DateTime.Now.ToLongTimeString();

}

 

In the Tick event handler, you update the user interface appropriately and let the page proceed with the rendering stage. At this time, the script manager orders a refresh of the markup for all the controls in the region bound to the timer s event.

 

Issues and Final Considerations

Asynchronous calls to remote URLs are more efficient if executed through script-callable services installed in the same domain as the calling application. Much less data is moved on the wire, and less work is required on the Web server. On the other hand, the developer needs to take care of any update to the user interface that is required once the response has been obtained. More importantly, any updates to the user interface must be conducted using JavaScript. This may be a problem for complex and sophisticated layouts. It s not an issue, instead, if all that you do is change a line or two of text.

 

Timer-based partial rendering is far easier to set up, but it moves viewstate and additional data between the two ends. As far as user interface updates are concerned, with partial rendering you can command changes using managed code and the object model of familiar ASP.NET server controls.

 

Overall, script services are the way to go; in ASP.NET 3.5, you can also implement them using the richer infrastructure of Windows Communication Foundation.

 

Dino Esposito is a mentor with Solid Quality Mentors (http://www.solidq.com) and specializes mainly in ASP.NET and AJAX solutions. He s the author of Introducing Microsoft ASP.NET AJAX (Microsoft Press, May 2007) and wrote the two volumes of Programming Microsoft ASP.NET 2.0, also for Microsoft Press. Late-breaking news is available at http://weblogs.asp.net/despos.

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish