Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Integrating AJAX

3.67/5 (3 votes)
27 Jan 20075 min read 1   490  
Here's a way to integrate AJAX into your .NET web applications without using Atlas

AJAX Integration

Introduction

This article goes over integrating AJAX into your website without using Atlas or controls that are already wired up for you. This is useful for environments where you cannot use Atlas. It's also interesting if you'd like a lower level look at how asynchronous client server communication works and the issues involved. The techniques covered include embedding JavaScript in the web application's assembly, registering variables from C# codebehind, and using AJAX to communicate with C# server side code.

Using the Code

To deploy the web application, just unzip the AJAXIntegration.zip into the inetpub\wwwroot directory. Then use the IIS snap in to create an application on the AJAXIntegration directory.

Project

One of the most common AJAX applications is an autocomplete text box. These are useful for maintaining data integrity and keeping input forms relatively uncluttered and intuitive. The key component is a nice JavaScript library from http://script.aculo.us/. This has, among other neat features, a good autocomplete implementation.

Points of Interest

The first thing we create is a web user control with a textbox and the necessary decoration and methods to hook into the scriptaculous library. I saved the scriptaculous library right in the root of my web project in a folder called Scriptaculous. The asp.net code for the user control looks like this:

HTML
<asp:TextBox id="TextBox1" runat="server" Width="300px">
    </asp:TextBox>
<div id="TextBoxUpdate" runat="server" style="BORDER: 
    #888 1px solid; DISPLAY: none; WIDTH: 250px; 
    CURSOR: pointer; POSITION: absolute; HEIGHT: 300px; 
    BACKGROUND-COLOR: white"></div>

Notice how there's no mention of the JavaScript. All the magic is in the codebehind, in the PreRender event. This event is called after most of the work to build the page is done. It is the right place to register client side scripts:

C#
private void AutocompleteTextBox_PreRender(object sender, 
                                        System.EventArgs e)
{
    this.Page.RegisterArrayDeclaration(
        "Tallan_AutocompleteTextBox","'"+
        SearchBox.ClientID+"','"+SearchBoxUpdate.ClientID+
        "','"+"http://localhost/AJAXIntegration/Fetch.aspx
            ?parameterId="+Parameter+"'");    

    string commonScriptKey = "AutocompleteTextBox";
    if ( !Page
        .IsClientScriptBlockRegistered(commonScriptKey) ) 
    {
        using (System.IO.StreamReader reader = 
                new System.IO.StreamReader(
                typeof(AutocompleteTextBox).Assembly
                .GetManifestResourceStream(typeof(
                AutocompleteTextBox),
                "AutocompleteTextBox.js"))
            )
        {
        // read the script
        String script = "<script language="'javascript'" 
            type='text/javascript' >\r\n<!--\r\n" + 
            reader.ReadToEnd() + "\r\n//-->\r\n</script>";

        // register the script and the init function
        this.Page.RegisterClientScriptBlock(
            commonScriptKey, script);
        this.Page.RegisterStartupScript(commonScriptKey, 
            "<script language="'javascript'" type='text
            /javascript' >\r\n<!--\r\n 
            Tallan_AutocompleteTextBox_Init(); \r\n//-->
            \r\n</script>");
        }
    }
}

The key technique here is using Page.RegisterArrayDeclaration, Page.IsClientScriptBlockRegistered, Page.RegisterClientScriptBlock and Page.RegisterStartupScript to handle the dynamic nature of ASP.NET user controls. What I mean by this is that a user control can be deployed on any page under any number of parent controls. Therefore its id will vary depending on where it resides. However, C# codebehind has access to that id, namely [some control].ClientId. So when the script is registered to the page, the JavaScript can operate with the correct controls on the client side. The Page.RegisterArrayDeclaration method will create a new JavaScript array in the HTML code that is pushed to the client. If the array exists, it will append to it. The other register methods are used to only register the script if one is not already present. This will be useful when you want to use more than one control on the same page, as I will in the example.

The other point of interest in the above code is how the scripts are fetched to be registered. In the Page.RegisterStartupScript call, I used inline text which will get written to the client as is. In the Page.RegisterClientScriptBlock however, I used a StreamReader to access an "Embedded Resource". The way this works is you make a JavaScript file and in Solution Explorer, right click and choose Properties. In the Build Action property, select the Embedded Resource choice. Now when you compile the project, this text file will be available to read as is shown above. As a little side note, if your JavaScript changes from these embedded resources aren't propagating to your deployed application, try rebuilding the project and redeploying it. This will make sure you have the freshest available copy of the script in the assembly.

The JavaScript file AutocompleteTextBox.js that is registered to the page contains an initialization method which is called by the page upon startup. It is this method that assigns the AJAX behavior to the textbox:

C#
function Tallan_AutocompleteTextBox_Init() {
    try
    {
        // Make sure the browser supports the DOM calls or 
        // JScript version being used.
        if (!Tallan_AutocompleteTextBox_BrowserCapable()) 
            { return; }
        // instantiate Ajax using the client ids
        for(var i=0;i<Tallan_AutocompleteTextBox.length; 
            i+=3 ){
            new Ajax.Autocompleter(
                Tallan_AutocompleteTextBox[i],
                Tallan_AutocompleteTextBox[i+1], 
                Tallan_AutocompleteTextBox[i+2], { 
                paramName: "search" });
        }
    }
    catch(e){}
}

Basically, the whole linkup is just instantiating a:

C#
new Ajax.Autocompleter

The constructor takes three parameters:

  • the client id of the text box to autocomplete
  • the client id of a div that will pop up and display the results
  • the url of a resource that will pass back autocomplete choices
  • the parameters for various scriptaculous options

The last thing to go over is the resource that supplies autocomplete choices. You can look up the scriptaculous parameters on their website as they continue to release updates and have a good documentation wiki.

Scriptaculous AJAX looks for a simple page that renders only an HTML list of the form:

HTML
<ul><li>autocomplete choice 1</li>
<li>autocomplete choice 2</li></ul> 

This is where we can create an aspx page (I called it Fetch.aspx) to hook into some server data source and render dynamic or cached autocomplete content. First, create a new web form in your project and make sure to delete everything in the generated source besides the page tag. This includes the form tag, html tag, everything. The reason for this is that Internet Explorer won't display the popup autocomplete div if the page is more complicated than just a simple <ul> list. Then, you're ready to write the following code in the Page_Load event:

HTML
string match = Request.Form["search"].ToLower();
Response.Write("<ul>");
foreach( string s in sample )
{
    if( s.ToLower().IndexOf(match) == 0 )
    {
        Response.Write("<li>"+s+"</li>");
    }
}
Response.Write("</ul>");

Notice how we get the "search" parameter from the Request.Form object. The name of this parameter is configured in the Ajax.Autocompleter constructor which is called in the Tallan_AutocompleteTextBox_Init function discussed above. The sample array is just a string[] of sample data. You can easily get your data from a DataTable using the Select method. In the AutocompleteTextBox control, I also included a property called Parameter which ends up being passed to Fetch.aspx in the query string like http://localhost/AJAXIntegration/Fetch.aspx?parameterId=[Parameter]. You can access this and any other properties you wish to pass from each individual control via the Request.QueryString object.

One last thing to note is that the SmartNavigation attribute confuses InternetExplorer's asynchronous request, at least when it comes to scriptaculous' implementation. Therefore, disable SmartNavigation on any page where the control will be used.

Conclusion

Now just deploy the code and try it for yourself. You can also open the project in Visual Studio or Sharp Develop and browse the code. Remember that you can enable script debugging in Internet Explorer by going to Tools, Options, Advanced and unchecking the "Disable script debugging" option. Doing so will allow you to place break points in the js files from the Scriptaculous folder and see what's going on during the asynchronous calls. I did not cover the full implementation details for the sake of brevity. Therefore, please don't hesitate to ask questions.

License

This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below. A list of licenses authors might use can be found here.