ASP.NET AJAX meets Virtual Earth – Part Two

Published: 2/22/2008
By: Alessandro Gallo

Get up to speed with ASP.NET AJAX by building a simple Virtual Earth mashup.

Introduction

In the first part of this series, we started with an example of a simple web page that displays a Virtual Earth map on screen. The purpose of the code was to highlight some bad habits in writing markup and JavaScript code. We promised ourselves to rewrite the same page in order to take advantage of ASP.NET and the new AJAX framework. This is what we are going to do starting from part two of this series.

Ajax-enabled Server Controls

One of the strength of the ASP.NET programming model is the ability to encapsulate the markup of a portion of the page and render it dynamically. The rendering logic is located inside an object called a Server Control. The responsibility of this object is simple: it determines which HTML will be written to the response stream, based on decisions made at runtime. This means that the generated markup can vary based on user preferences, environment configuration, and business logic. The dynamic generation of the HTML of a web page is the main philosophy behind server technologies like ASP.NET.

As a consequence, our ASP.NET AJAX page will contain a Panel control, which is responsible for rendering the div element that hosts the Virtual Earth map:

So far, everything is straightforward. In order to host a Virtual Earth map inside the div element, we need a Server Control that performs two tasks:

The code in listing 1 shows this Server Control declared in the ASP.NET AJAX page.

Listing 2: The VirtualEarthExtender control is an Ajax-enabled server control

The Server Control in the previous listing is not a typical ASP.NET control. In fact, it's a new kind of control - provided by ASP.NET AJAX - called an Extender.

One reason for creating an Extender is that it lets you inject a script tag programmatically by instantiating an object of type ScriptReference. However, this can be done with classic ASP.NET controls, simply by invoking one of the methods of the ClientScriptManager object, which is accessible through the Page.ClientScript property. Actually, we are already gaining something because we are encapsulating this logic inside a dedicated object, instead of interacting directly with the ClientScriptManager class.

Where the Extender really shines is in its ability to instantiate and set up JavaScript objects. How can you do that with classic ASP.NET? Well, you could build the JavaScript code as a big string and inject it in the page using the ClientScriptManager. No need to say, this isn't a good approach. With ASP.NET, we can render markup dynamically, and yet we're relying on strings in order to inject JavaScript code in the page.

With an Extender, we can solve this problem in the following way: we can associate a special JavaScript object, called a client Control, to a HTML element in the page. In terms of ASP.NET markup, this means creating an Extender and associating it with another Server Control - the "extended" control. Take a look at listing 1. Notice how we are associating the VirtualEarthExtender to the Panel through the TargetControlID property.

At this point, the Extender is able to generate the JavaScript code needed to create an instance of the client Control and wire it to the HTML rendered by the extended control (the Panel in our example). Furthermore, we can control - from the server side- how the JavaScript object is initially configured.

Based on the previous discussion, this is what you are going to do in the following paragraphs:

Client Controls

ASP.NET AJAX ships with a client library - written in JavaScript - called the Microsoft Ajax Library. With the help of this library, you will create a client Control that encapsulates an instance of a Virtual Earth map.

Why create a wrapper over a VEMap object? There are multiple reasons. One is that the Microsoft Ajax Library enables you to do component-based development on the client side. However, what interests us now is the possibility to use a client Control to manage the lifecycle of our JavaScript object. Let's start by taking a look at the following listing, which reports the code for the Mashup.VirtualEarth client Control.

Listing 3: Mashup.VirtualEarth Control

The first line tells the Microsoft Ajax Library to create a namespace called Mashup. Under this namespace, the VirtualEarth control is declared as a function and then registered as a Control. This happens in the last line - the first after the function body - through the call to the registerClass method. This method "upgrades" our JavaScript function to an ASP.NET AJAX client class and makes it inherit from Sys.UI.Control, which is the base class for client Controls.

Note: The Microsoft Ajax Library lets you create namespaces and classes in JavaScript. We usually refer to these and other constructs as "object-oriented patterns".

The base Sys.UI.Control class provides two interesting methods called initialize and dispose. These are the best places to perform the initial setup and the final cleanup of an instance. An example is attaching event handlers in the initialize method and then detaching the same handlers in the dispose method. As a consequence, this lets you abandon the bad habit of hooking-up event handlers in the HTML. Furthermore, it enables you to detach handlers before the instance is destroyed, thus avoiding potential memory leaks.

Managing the lifecycle of a JavaScript object is a good practice, and it's just one of the many features provided by client Controls. Finally, look at how the Mashup.VirtualEarth function is declared. It accepts an argument called element and passes the same argument to the base class by calling the initializeBase method. Every client Control is associated with one and only one HTML element. In this example, the associated element will act as the container for the Virtual Earth map, since it's being passed to the VEMap constructor inside the initialize method.

Now that you've got a client Control, you need to wire it to a server Control - an Extender. This will enable you to instantiate and configure the client Control from the server side, without writing a single line of JavaScript code.

The VirtualEarth Extender

Now you are going to create a VirtualEarth Extender that lets you instantiate and configure an instance of the Mashup.VirtualEarth client Control. To create an Extender, you have to declare a class that inherits from the base ExtenderControl class, as shown in the following listing.

Listing 4: Declaring an Extender

Just before the class declaration, there's a TargetControlType attribute that specifies which server Controls can be extended by our VirtualEarth Extender. In this case, you are restricting the extended Control to be a Panel, since it will render the div element that will host the Virtual Earth map.

The next thing to do is declare some properties that allow setting the values of the counterpart properties of the client Control. The following listing shows how it's done.

Listing 5: Mapping server properties to client properties

The InitialLatitude and InitialLongitude properties let you specify the coordinates of the initial location at which the map is centered. When the Mashup.VirtualEarth instance is created on the client side, these values are mapped to the initialLatitude and intialLongitude properties. The same thing happens for the ZoomLevel property. The purpose of these server properties is to let the developer configure a JavaScript object - specifically, a client Control - from the server side.

Finally, we need to write the code that creates an instance of the client Control and injects the references to the script files that contain the JavaScript code. You accomplish this task by overriding two methods of the base ExtenderControl class: GetScriptReferences and GetScriptControls. This is demonstrated in the following listing.

Listing 6: Working with Script Descriptors and Script References

The GetScriptReferences method returns a collection of ScriptReference objects. Each object specifies the path to a JavaScript file. These paths (or URLs) will be injected in a script tag rendered in the page by the ScriptManager control.

The RegisterScriptDescriptors method returns a collection of ScriptDescriptor objects. Script Descriptors are used by the ScriptManager to render the JavaScript code necessary for creating and configuring an instance of a client component. In this case, we are using a ScriptControlDescriptor because we are going to instantiate a client Control.

Behind the Scenes

Now that the Extender is ready, let's browse the ASP.NET page and take a look at the source code. The first thing to notice is that the VirtualEarth Extender injected two script tags, just after those that reference the Microsoft Ajax Library files:

The first script tag references the Virtual Earth API, using the default URL or the one specified in the ApiUrl property of the Extender. The second script tag references the Mashup.VirtualEarth client Control. Both these scripts were referenced in the GetScriptReferences method of the Extender.

Finally, let's take a look at the JavaScript code injected in the page by the Virtual Earth Extender:

Sys.Application is a global object created by the Microsoft Ajax Library at runtime. This object accomplishes some interesting tasks, such as hosting the client components instantiated on the client side. By calling the add_init method, you can participate in the Init stage of the client side page lifecycle. There, you have the opportunity to instantiate and configure the Mashup.VirtualEarth client Control. You can do that by calling the $create method and passing the configuration parameters, as shown in the previous code snippet. Not only does $create offer a convenient syntax to instantiate client Controls; it also allows Extenders to leverage the same syntax in order to automatically create instances of client components at runtime. As you can see, everything has been setup on the server side, without actually writing a single line of JavaScript code.

In the next part of this series, we will expand our Virtual Earth Control and explore other kinds of interactions between the server side and the client side of an ASP.NET AJAX Web Application.

Summary

In the second part of this introduction to ASP.NET AJAX, we introduced client Controls and Extenders. Thanks to the Microsoft Ajax Library, we can do component-based development on the client side. We are able to encapsulate JavaScript code into a component that can be initialized, set up and disposed in a standard way.

By creating an Extender, we can wire a client Control to a server Control. Then, we can configure the client Control on the server side through the Extender's properties. Finally, Extenders take care of injecting in the page the necessary script references and the JavaScript code that instantiates a client component.

Please visit the link at the below url for any additional user comments.

Original Url: http://dotnetslackers.com/columns/ajax/ASPNETAJAXMeetsVirtualEarthPartTwo.aspx