Extend ASP.NET AJAX Client-Side Function - The Server-Side Way
Published: 13 Nov 2007
In this article the author examines the different ways to extend ASP.NET AJAX client-side function from the server- side with the help of sample applications.
by Xianzhong Zhu
Average Rating: 
Views (Total / Last 10 Days): 55685/ 183


In my previous article entitled Explorer Ways to extend ASP.NET AJAX Client-side Function, we only, from the client side’s point of view, focused on adding the client-side functionalities and behaviors to the current ASP.NET AJAX framework. However, creating custom ASP.NET AJAX client-side components is a pretty intensive work in JavaScript. While some ASP.NET developers are able to write JavaScript code, others may not have a complete understanding of the language and may prefer to use server-side objects that can be manipulated using VB.NET or C#. On the other hand, because server-side controls can output both HTML and JavaScript, they are good candidates for use with ASP.NET AJAX client-side components. In this article we will explore ways to extend ASP.NET AJAX client-side function from the server side.

About ExtenderControl

According to the online materials and all possible existing references, there are typically two means, from the server side, to enable us to expand the client-side functionalities of ASP.NET AJAX framework. The first path to follow is to create a separate ExtenderControl (Listing 1 gives the class definition and Figure 1 depicts a more vivid hierarchical tree for it), which encapsulates client capabilities in a behavior and that can then be attached to an ASP.NET Web server control.

Listing 1

public abstract class ExtenderControl : Control, IExtenderControl{
      // Fields
      private IScriptManagerInternal _scriptManager;
      private string _targetControlID;
      // Methods
      protected ExtenderControl();
      internal ExtenderControl(IScriptManagerInternal scriptManager);
      private static UpdatePanel FindUpdatePanel(Control control);
      protected abstract IEnumerable<ScriptDescriptor> 
       GetScriptDescriptors(Control targetControl);
      protected abstract IEnumerable<ScriptReference> GetScriptReferences();
      protected override void OnPreRender(EventArgs e);
      private void RegisterWithScriptManager();
      protected override void Render(HtmlTextWriter writer);
      IEnumerable<ScriptDescriptor> IExtenderControl.GetScriptDescriptors(
       Control targetControl);
      IEnumerable<ScriptReference> IExtenderControl.GetScriptReferences();
      // Properties
      private IScriptManagerInternal ScriptManager { get; }
       [DefaultValue(""), ResourceDescription("ExtenderControl_TargetControlID"), 
       IDReferenceProperty, Category("Behavior")]
      public string TargetControlID { get; set; }
      public override bool Visible { get; set; }


Figure 1 - The hierarchical tree related to ExtenderControl

As for the IExtenderControl Interface and all related details, we will delve into them later on. For now, what we should be aware of is that an extender control itself is not part of its associated controls; therefore, we can create a single extender control that can be associated with several types of ASP.NET Web server controls.

About WebControl

Another path to extend ASP.NET AJAX client-side functionalities is via script controls. Script controls are WebControls that can provide script references and script descriptors (i.e. implementing IScriptControl) without relying on an external object (like the first means). We can describe both the server-side and the client-side functionalities in a single place.

In general, if we want to develop the control from scratch, we can safely derive from the base ScriptControl class, which takes the responsibility for registering the script control with the ScriptManager under the hood. Joyfully, programming the control is pretty similar to doing an extender.

One point to note is that the IScriptControl interface, similar to interface IExtenderControl, must be implemented by every script control. Another point to note is that a script control does not have a target control; this is why the RegisterScriptDescriptors method (also to be discussed later) does not receive a reference to the extended control as happened with extenders.

To make clearer the relationships between the objects mentioned above, we list the class definition for class ScriptControl in Listing 2 and give a hierarchical tree between the associated objects in Figure 2.

Listing 2 - The class definition for class ScriptControl

public abstract class ScriptControl: WebControl, IScriptControl
  // Fields
  private IScriptManagerInternal _scriptManager;
  // Methods
  protected ScriptControl();
  internal ScriptControl(IScriptManagerInternal scriptManager);
  protected abstract IEnumerable < ScriptDescriptor > GetScriptDescriptors();
  protected abstract IEnumerable < ScriptReference > GetScriptReferences();
  protected override void OnPreRender(EventArgs e);
  protected override void Render(HtmlTextWriter writer);
  IEnumerable < ScriptDescriptor > IScriptControl.GetScriptDescriptors();
  IEnumerable < ScriptReference > IScriptControl.GetScriptReferences();
  // Properties
  private IScriptManagerInternal ScriptManager

Figure 2 - The hierarchical relationships related to ScriptControl

Now, with a general profile in mind, let us examine carefully the above two solutions.

The ExtenderControl Way

We have already known that an extender’s goal is to wire a client component to an existing server control. Therefore, we have to make clear how the client functionality is attached to the extended control.

The easiest way to build an extender is to declare a class that inherits from the base ExtenderControl class. This class implements an interface called IExtenderControl and takes care of registering the extender with the ScriptManager control. A derived class should override the methods defined in the IExtenderControl interface. Let us look more closely into this interface before developing our first extender.

The IExtenderControl Interface and Registering the Extender

The IExtenderControl interface defines the contract to which a class adheres to become an extender. Listing 3 shows the methods implemented by the interface and Table 1 gives the detailed explanations.

Listing 3

public interface IExtenderControl
  IEnumerable<ScriptDescriptor> GetScriptDescriptors(Control targetControl);
  IEnumerable<ScriptReference> GetScriptReferences();

Table 1




Returns a collection of script descriptors that represent JavaScript components on the client.  This method is used to map server-side control properties to client-side control properties.


Returns a collection of ScriptReference objects that define script resources required by the control.  This method is used to identify one or more embedded script resources in a control assembly and output them to the client.

The process of registering with the ScriptManager lets the extender be recognized as an Ajax-enabled control. Concretely, this is a two-step process:

1 During the PreRender stage, we will call RegisterExtenderControl method, passing the extender instance and the extended control as arguments.

2 During the Render stage, we will call the RegisterScriptDescriptors method to register the script descriptors.

The first part of the registration procedure involves calling the RegisterExtenderControl method on the ScriptManager control. This method receives the current extender instance and the extended control as arguments. The registration procedure is completed during the Render phase, where you call the RegisterScriptDescriptors method on the ScriptManager, passing the current extender instance as an argument.

Happily, the ExtenderControl class takes care of performing the registration procedure automatically.  Since we always create a new extender by deriving from the ExtenderControl class, we do not need to worry about the implementation details.  As for script controls to be discussed later, however, we will discover that in some situations we need to manually register the Ajax-enabled control with the ScriptManager.

In the following section, we will create an extender for the MyHoverBehavior behavior we built in earlier article "Explorer Ways to extend ASP.NET AJAX Client-side Function."  This will let you wire the behavior to an ASP.NET Panel control (you can of course try other types of controls) and configure it on the server side.

Sample 1

In the earlier article "Explorer Ways to extend ASP.NET AJAX Client-side Function," we demonstrated how to enrich an HTML <div> element by setting different CSS styles when the mouse hovers/unhovers over it with the help of a client behavior. Now that we have implemented this client component, it is pretty suitable to build an extender to wire it to ASP.NET server controls in different web applications. And since we have the code for the MyHoverBehavior class stored in a JavaScript file we have completed the first phase of the whole process and can move to the second phase.

Create an ASP.NET AJAX-enabled Web Site

Launch Visual Studio 2005 and select template "ASP.NET AJAX-enabled Web Site" to create a web site named ServHoverBehavior, as well as select Visual C# as the built-in language. Next, right click the project and select "New folder" to create a folder named ScriptLibrary. Then we can, for brevity, copy the JScript file MyHoverBehavior.js (although it was created in Sample 1 in the above-mentioned earlier article we should have to make a little modification with it later) to this folder.

Also, we can copy file intro.css to the root folder of this website. And also, for easier debugging the JScript file MyHoverBehavior.js, we had better add a reference to assembly System.Web.Extensions.dll, which will result in a Bin folder in the website.

Now, we are ready to move to the next phase to create a server-side extender class and implement the server-side logic.

Create the Server-side Extender Class

1. Mapping client properties to the server ones

Now that the client functionality has been encapsulated in a client component, we need to filter the client properties that we want to configure on the server side so that we can create corresponding properties in the extender class and use them to set the value of the client properties. All that makes this possible is use a script descriptor.

To set their values from the server side, we need to expose corresponding properties in the extender. For more clarity, we can draw a table to illustrate the relationship between the properties of the two components we are to create in JavaScript.

Table 2—mappings between client properties and extender ones

Client property

Extender property







2. Creating the extender

As mentioned above, an extender is a class that inherits from the base System.Web.UI.ExtenderControl. Therefore, we can simply right-click the project and add a class named ServHoverBehavior, which will result in generating an App_Code sub folder automatically by the system.

Next, we should let the class derive from ExtenderControl, adding the necessary server-side properties and overriding the related methods defined in the IExtenderControl interface. Here, we directly listed the related source code.

Listing 4

namespace ZXZSamples.CS
  public class ServHoverBehavior: ExtenderControl
    public int UnhoverDelay
        return (int)ViewState["UnhoverDelay"];
        ViewState["UnhoverDelay"= value;
    public string HoverScript
        return (string)ViewState["HoverScript"];
        ViewState["HoverScript"= value;
    public string UnhoverScript
        return (string)ViewState["UnhoverScript"];
        ViewState["UnhoverScript"= value;
    public string ScriptPath
        return (string)ViewState["ScriptPath"];
        ViewState["ScriptPath"= value;
    protected override IEnumerable < ScriptDescriptor > GetScriptDescriptors
      (Control targetControl)
      ScriptBehaviorDescriptor desc = new ScriptBehaviorDescriptor(
        "ZXZSamples.MyHoverBehavior", targetControl.ClientID);
      desc.AddProperty("unhoverDelay", this.UnhoverDelay);
      desc.AddProperty("hoverScript", this.HoverScript);
      yield return desc;
    protected override IEnumerable < ScriptReference > GetScriptReferences()
      yield return new ScriptReference(Page.ResolveClientUrl(this.ScriptPath));

First, by putting above the class declaration a TargetControlType attribute we put a constraint on the types of server controls that the extender can extend (since we specify the type is Control we can wire the behavior to nearly any ASP.NET server controls).

Next, we expose a ScriptPath property which is used to specify the location of the JavaScript file that contains the code of the MyHoverBehavior behavior. The property is not listed in the above table because it is not exposed by the client component. However, we will need it when creating the ScriptReference instance. All the other properties store the values assigned to the corresponding properties of the client behavior. Note, here we store and retrieve all the values from the ViewState of the extender control.

As for the last two overridden methods, method GetScriptDescriptors takes care of returning a script descriptor for the MyHoverBehavior behavior. In the override, the script descriptor uses the values of the server UnhoverDelay, HoverScript, and UnhoverScript properties to build a $create statement that contains values for the client related properties, while method GetScriptReferences returns a ScriptReference instance with the information needed to load the right JavaScript file in the page.

Author's Note: In the above JScript file, MyHoverBehavior.js, we introduced two new properties hoverScript and unhoverScript. Therefore, here appear their corresponding server-side properties. These two properties hold two pieces of the related JavaScript code snippet that corresponds respectively to the hover and unhover events of the behavior. When the events fire, with the help of function eval of JavaScript, we execute the JavaScript code snippet held inside the above two properties—hoverScript and unhoverScript. You can find the similar implementation in the source code of entender HoverExtender shipped with AjaxControlToolkit.

Using the ServHoverBehavior extender

In fact, an extender is nothing more than a custom ASP.NET server control. Therefore, we can follow the same rules as any other server control to register and declare an extender in an ASP.NET page.

To use the above extender in an ASP.NET page, all we have to do is register the namespace that contains the ServHoverBehavior class in the page that will use it:

<%@ Register Namespace="ZXZSamples.CS" TagPrefix="samples" %>

Now, it is time to wire the extender to its target control. Listing 5 shows an ASP.NET Panel control with an associated ServHoverBehavior control in our sample.

Listing 5 - Extending an ASP.NET web control declaratively

<asp:Panel ID="panel1" runat="server" Height="37px" Width="354px" 
Move the mouse over ME and watch!
<samples:ServHoverBehavior ID="MyHoverBehaviorExtender1" runat="server" 
UnhoverDelay=30 HoverScript="SetHoverCSS();" UnhoverScript="SetUnhoverCSS();">

All the magic of extenders happens when we set the extender control’s Target-ControlID property to the ID of the target control. Here, we extend the Panel by assigning its ID to the TargetControlID property of the ServHoverBehavior control. The ScriptPath property contains the path to the MyHoverBehavior.js file. Note the two properties HoverScript and UnhoverScript are assigned to two strings that hold two JavaScript functions respectively.

In addition, we should notice that at the start up of the web page we have to set the proper CSS style to the Panel control to make the test result more attractive:

function pageLoad()
  document.getElementById("<%=panel1.ClientID %>").className='start';

As for the two above-mentioned methods, Listing 6 gives their simple programming.

Listing 6

function SetHoverCSS()
  document.getElementById("<%=panel1.ClientID %>").className='hover';
function SetUnhoverCSS()
  document.getElementById("<%=panel1.ClientID %>").className='start';

Easy enough, isn't it? When the mouse hovers over the Panel, the style of the panel is set to "hover" (Figure 3) while when the mouse leaves (unhovers) the Panel the style is set (restored) to "start" (Figure 4). Here the two styles (hover and start) are both defined within file intro.css.

Figure 3 - When the mouse hovers over the Panel, the style of the panel is set to "hover"

Figure 4 - When the mouse leaves the Panel, the style of the panel is set to "start"

As we mentioned in the earlier articles, the <textarea> (with id being "TraceConsole") at the bottom of the two snapshots will facilitate the debugging of JavaScript files.

Further Discussion

To get better ideas of what we discussed above, when we run the above ASP.NET sample page we can further dig into the source code sent to the browser.  Here, what most interests us is the $create statement generated by the script descriptor that the ServHoverBehavior returned to the ScriptManager control.

Listing 7

<script type="text/javascript">
Sys.Application.add_init(function() {
    $create(ZXZSamples.MyHoverBehavior, {"hoverScript":"SetHoverCSS();", 
"unhoverDelay":30, "unhoverScript":"SetUnhoverCSS();"}, null, null, 
// -->

Note how the $create statement is correctly injected into a JavaScript function that handles the init event raised by Sys.Application.

Now that everything goes smooth with the Extender, we are ready to explore the second category of extending ASP.NET AJAX client-side functionalities—the WebControl way.

The WebControl Way

Extenders are great for providing client functionality to existing server controls in an incremental way. In many cases, however, we do not want or do not need an external control to wire client components to a server control. To describe both the server-side and the client-side functionalities in a single place, we can resort to script controls. In fact, Script controls are ASP.NET server controls that can provide script references and script descriptors without relying on an external object.

Generally, if we are writing the control from scratch, we can safely derive from the base ScriptControl class, which takes care of registering the script control with the ScriptManager under the hood. The only difference between coding the control and coding an extender is that the properties used to configure the client component and the overrides of the methods defined in the IScriptControl interface are embedded in the control rather than in a different object.

In some cases we may want to convert an existing control into a script control. In such a case we have to derive a class from the existing server control and manually implement interface IScriptControl.

The following sections will introduce to you the IScriptControl interface.

The IScriptControl Interface and Registering the Script Control

The IScriptControl interface defines two methods; Listing 8 and the following Table 3 describe their respective functionalities:

Listing 8

public interface IScriptControl
  IEnumerable<ScriptDescriptor> GetScriptDescriptors();
  IEnumerable<ScriptReference> GetScriptReferences();

Table 3




Gets a collection of script descriptors that represent JavaScript components on the client. This method is used to map server-side control properties to client-side control properties.


Gets a collection of ScriptReference objects that define script resources required by the control. This method is used to identify one or more embedded script resources in a control assembly and output them to the client.

Registration with the ScriptManager is necessary in order to recognize a script control as an Ajax-enabled control.  It is a two-step process similar to that used for extenders.

1. During the PreRender stage, we call the RegisterScriptControl method, passing the script control instance as an argument.

2. During the Render stage, you call the RegisterScriptDescriptors method to register the script descriptors.

Here we are unwilling to chatter too much about the pure theories. Thus, let us make room for a simple sample to let it tell every detail.

Sample 2

In my opinion, to build a server-side ASP.NET AJAX control is even more complex than to build a client-side one. On the one hand, control developers must be familiar with the fundamentals to construct ASP.NET Server controls; on the other hand, they still have to grasp the client-side DOM, JavaScript, and ASP.NET AJAX client-side programming. Of course, they can be divided into two groups—one takes care of the server-side techniques while the other does the client-side ones. This means the whole process of developing a server-side ASP.NET AJAX control can be simplified. In real scenarios this is usually not the case. However, there are still many reasons to explorer the means to develop server-side ASP.NET AJAX controls. For example, the common web page developers can more easily and conveniently work with these controls using standard ASP.NET control syntax without worrying about writing custom JavaScript code or even using the ASP.NET AJAX script library’s $create() method to instantiate the controls.

Since we are to write a visual menu control from scratch that generates HTML and JavaScript, we will get the control derived from System.Web.UI.WebControl and implement the IScriptControl interface. And, at the same time, the menu control will continue to leverage the "AjaxMenuCtrl.js" client-side control script discussed in the earlier article "Explorer Ways to extend ASP.NET AJAX Client-side Function."

Author's Note: In this sample below, we will embed the related scripts in the server-side controls. Of course, you can also place the related resources used by the control assembly outside it. For details about this, you can refer to related topics in MSDN.

Creating a WebControl Class that Implements IScriptControl Interface

1. Start up Visual Studio 2005 and create a new WebControl library called AJAXServMenuLib.

2. Right-click the project and select "Add References…" to add a reference to the System.Web.Extensions.dll assembly. This is a must have because IScriptControl interface is defined within namespace "System.Web.UI" defined inside "System.Web.Extensions" namespace.

3. Add a new JavaScript file called AjaxMenuCtrl.js. Right click it and, in the Properties panel, set the Build Action property to "Embedded Resource."  In this way, the compiler can embed the file as an assembly resource that can be loaded in a web page.

4. To make the above script accessible, add the following assembly attribute immediately above the server control’s namespace definition.

[assembly: System.Web.UI.WebResource("AJAXServMenuLib.AjaxMenuCtrl.js""text/javascript")]
namespace AJAXServMenuLib

This makes the script accessible through an HttpHandler built into ASP.NET AJAX called ScriptResource.axd and avoids having to deploy the physical script file along with the server control assembly, which can greatly simplify deployment and maintenance. The WebResource attribute’s constructor accepts the name of the resource followed by the content-type of the resource. Note that the name given to the resource is the assembly name followed by the name of the script.

5. Implement interface IScriptControl.

As is emphasized above, to make the server control ajaxified we should implement IScriptControl interface as follows:

Listing 9

public class AJAXServMenuCtrl: WebControl, IScriptControl
  //Properties and methods definitions…
  protected virtual IEnumerable < ScriptDescriptor > GetScriptDescriptors()
    ScriptControlDescriptor descriptor = new ScriptControlDescriptor(
      "Samples.AjaxMenuCtrl", this.ClientID);
    descriptor.AddProperty("MenuListCssClass", this.MenuListCssClass);
    return new ScriptDescriptor[]
  protected virtual IEnumerable < ScriptReference > GetScriptReferences()
    ScriptReference r = new ScriptReference();
    r.Assembly = "AJAXServMenuLib";
    r.Name = "AJAXServMenuLib.AjaxMenuCtrl.js";
    return new ScriptReference[]
  IEnumerable < ScriptReference > IScriptControl.GetScriptReferences()
    return GetScriptReferences();
  IEnumerable < ScriptDescriptor > IScriptControl.GetScriptDescriptors()
    return GetScriptDescriptors();

Here, with two helper functions, GetScriptDescriptors and GetScriptReferences, we have implemented two methods declared inside interface IScriptControl.

The GetScriptReferences() method shown above creates a ScriptReference object and identifies the script resource that the server control needs to send to the client (AJAXServMenuLib.AjaxMenuCtrl.js, in this case). The GetScriptDescriptors() method creates a new ScriptControlDescriptor object that maps server-side control properties to client-side control properties. This is necessary so that the property values set on the control by a developer can be passed to the $create() method used to instantiate the client-side control. Note that the properties defined in this server-side control are quite the same ones discussed in my earlier article.

6. Overriding Render and OnPreRender

Once our custom AJAXServMenuCtrl control’s script resources are identified and server-side properties are mapped to client-side properties, the control should override the WebControl's OnPreRender method and retrieve a reference to the ScriptManager object in the page. The ScriptManager object is then used to register the AJAXServMenuCtrl control as a script control by calling the ScriptManager’s RegisterScriptControl() method.

Also, this server-side control should override the WebControl's Render method to register the property mappings (referred to as script descriptors) returned from the GetScriptDescriptors() method. This serves the purpose of passing the control’s property values defined on the server-side to the $create() method generated automatically by the ScriptManager control. Listing 10 shows the two methods.

Listing 10

protected override void OnPreRender(EventArgs e)
  if (!this.DesignMode)
    _ScriptManager = ScriptManager.GetCurrent(Page);
    if (_ScriptManager == null)
      throw new HttpException(
        "A ScriptManager control is required in the page.");
protected override void Render(HtmlTextWriter writer)
  if (!this.DesignMode)

7. Build the project and generate the final assembly—AJAXServMenuLib.dll.

Using a Custom ASP.NET AJAX Control in an ASP.NET Page

First, open menu "File->Add…," click "New Website…" and select "ASP.NET AJAX-based Web Site" template to create a sample website named AJAXServMenu.

Second, right-click the website and add reference to the above newly-generated assembly.

Third, to use the server control AJAXServMenuCtrl in page "Default.aspx," we have to first register the control in the page by using the following Register directive:

<%@ Register Assembly="AJAXServMenuLib" Namespace="AJAXServMenuLib"  TagPrefix="ajax" %>

This directive references the assembly name (AJAXServMenuLib), the namespace that the control resides in (AJAXServMenuLib), as well as the tag prefix (ajax) that should be used to define the control in this page. Once registered, this control can be used in the page just the same as any other ASP.NET server control. What we merely need to do is define the tag prefix and class name followed by all of the necessary properties in the Register directive. In this case, the related code is shown below.

Listing 11

<ajax:AJAXServMenuCtrl ID="divAjaxMenu" runat="server"  MenuTitle="Topics"
MenuTopCssClass="menutop" MenuListCssClass="menulist" 
ServicePath="MenuService.asmx" ServiceMethod="GetMenuData" Width="500px" />

Once the page is called by an end user through a browser, the necessary client-side script code used by control AJAXServMenuCtrl will automatically be added to the rendered output by the ScriptManager control.

Now, just press F5 and watch what happens. Figure 5 corresponds to one of the run-time snapshots.

Figure 5 - One of the run-time snapshots for Sample 2

Author's Note: Here, I omit the analysis of the generated HTML code on the browser, but I highly recommend readers to examine it themselves to make clearer the mechanisms behind the scenes.



In this article we have discussed two typical ways (ExtenderControl and WebControl) to enhance ASP.NET AJAX framework's client-side functionality from the point view of the server side. First, we should be aware that to construct Ajax-enabled server controls we must be quite familiar with the concepts of script descriptors and script references, which are the main objects used by server controls to instantiate client components and load script files in a web page. Second, the two related samples provided in this article are still pretty elementary with still much to be improved. Third, in contrast with the methods introduced in the earlier article "Explorer Ways to extend ASP.NET AJAX Client-side Function," the ways introduced in this article are not easy to grasp either. In fact, to follow the server-side way to construct an AJAX-enabled control we have to gain a good understanding with the ASP.NET server control development as well as the JavaScript techniques. However, apparently the server-side solution greatly lessens the burden the ASP.NET developers bear.

In real scenarios, to develop ASP.NET AJAX based components (or controls) we should first do careful research into the practical requirements as well as the developers' familiarities with necessary developing tools. Then the next thing for us to do is to decide which solution to follow to develop which kind of component.


User Comments

No comments posted yet.

Community Advice: ASP | SQL | XML | Regular Expressions | Windows

©Copyright 1998-2019 ASPAlliance.com  |  Page Processed at 2019-03-23 9:30:11 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search