16.2. Ajax.NETMichael Schwarz, a German MVP for ASP and ASP.NET, published his free Ajax.NET library some time ago. It offers Ajax functionality (data exchange 316ith the server, including serialization of many data types), client callbacks, and some advanced features. The source code for Ajax.NET was eventually released to the public (see http://weblogs.asp.net/mschwarz/archive/2005/08/11/422293.aspx) and development on the library stopped. However, the code has since been moved into the BorgWorX project (see http://www.borgworx.net). Schwarz went on to work on Ajax.NET Professional (http://www.ajaxpro.info), which is available under a closed-source license, but is still free. Ajax.NET and Ajax.NET Professional can both be used with ASP.NET 1.1 and 2.0.
This section focuses primarily on the original Ajax.NET release but also briefly describes how to migrate an application to Ajax.NET Professional. This discussion is not meant to provide an exhaustive guide to these libraries, but just as a teaser, showing the basic functionality and one or two advanced features to whet your appetite. 16.2.1. Using Ajax.NETTo use Ajax.NET, download the Ajax.dll library from the Ajax.NET web site (http://ajax.schwarz-interactive.de). Recently, this URL redirects to another site, but the .dll file used in this example is still available from http://ajax.schwarz-interactive.de/download/ajax.zip. In Visual Studio, start a new web site (the Ajax.NET settings would collide with the Atlas settings in the Web.config file) and add a reference to Ajax.dll, or just copy the Ajax.dll assembly to the application's Bin directory. Doing so provides you with IntelliSense support for the library, as Figure 16-2 shows. Figure 16-2. Ajax.NET integrates into Visual Studio and provides IntelliSenseCreate a new ASP.NET page and import the Ajax namespace that is provided by Ajax.NET. Important: the current page must have an (arbitrary) class name: <%@ Page Language="C#" ClassName="AjaxNETExample" %> <%@ Import Namespace="Ajax" %> Then, in the Page_Load() method, register the current page with Ajax.NET. That's what you need the class name foryou have to provide its type to the RegisterTypeForAjax() method, like this: protected void Page_Load(object sender, EventArgs e) { Ajax.Utility.RegisterTypeForAjax(this.GetType()); } From this point, using the Ajax.NET library is easy and intuitive. On the server side, you implement the "business logic"for our example, we will once again square a number. Ajax.NET provides a set of attributes you can use to identify Ajax.NET-enabled portions of your code. The [Ajax.AjaxMethod()] attribute makes any method accessible through JavaScript. The following code creates a server-side function called squareNumber(); the Ajax.AjaxMethod() attribute will cause the library to create a JavaScript proxy for the method. [Ajax.AjaxMethod()] public int squareNumber(int a) { return Convert.ToInt32(Math.Pow(a, 2)); } And this is all that is required in server-side code! The rest is JavaScript. An HTML form contains a text field that expects a number to be squared as a parameter and calls a client-side function in response. In our example, this function will be called callComplete(). (This name does not exactly convey the purpose of this function, but it's a name we have used all over this book, so it is recycled here.) Here is the page markup, showing the call to the callComplete() method: <form runat="server"> <div> <nobr> <input type="text" name="a" size="2" /> <sup>2</sup> = <span style="width: 50px;" ></span> </nobr> <br /> <input type="button" value="Square Number" onclick="callComplete(this.form)" /> </div> </form> The callComplete() function itself calls the server squareNumber function by using a client proxy. The proxy is generated automatically by Ajax.NET. In the example, the proxy can be accessed using AjaxNETExample.squareNumber(). Here is the code for the callComplete() function: <script language="JavaScript" type="text/javascript"> function callComplete(f) { var result = AjaxNETExample.squareNumber( parseInt(f.elements["a"].value)); document.getElementById("aSquare").innerHTML = result.value; } </script> The result returned from the server-side function has three properties:
In the example, we use only the value property, but a real-world application obviously requires an extra layer of error handling and should test the error property as a minimum. One more step is required. The call to the RegisterTypeForAjax() method places elements similar to these into the page markup: <script type="text/javascript" src="/books/3/491/1/html/2//AjaxNET/ajax/common.ashx"></script><script type="text/javascript" src="/books/3/491/1/html/2//AjaxNET/ajax/ASP.AjaxNETExample,App_Web_duood5sl .ashx"></script> (This assumes that the current web application is called AjaxNET.) But the files referenced in the src attributes do not exist yetAjax.NET consists only of the Ajax.dll assembly. The ajax subdirectory does not exist, either. To make all of this work (that is, to virtualize the files and folders referenced in the markup), you must place the following directive in the Web.config file as a child of the <system.web> section: <httpHandlers> <add verb="POST,GET" path="ajax/*.ashx" type="Ajax.PageHandlerFactory, Ajax" /> </httpHandlers> This enables Ajax.NET to parse the current page, look for all methods with the Ajax.AjaxMethod() attribute, and create the JavaScript proxy objects, making the whole application work. Example 16-3 shows you the complete code, which as you can see is quite compact
Example 16-3. Using Ajax.NET
Figure 16-3 shows the results of loading Example 16-3, entering a number, and clicking the Square Number button. Figure 16-3. Squaring numbers with Ajax.NETYou might have noticed that this is a synchronous communication, even though the current Ajax implementations typically use an asynchronous call. But it is trivial to extend the example so that an asynchronous callback function is used. To do so, you just provide an extra parameter to the server function you call using JavaScriptnamely, a reference to the callback function. Then, this callback function automatically gets the result. Example 16-4 shows the complete markup and script for the preceding example, this time using asynchronous communication, with changes highlighted in the code. Example 16-4. Using Ajax.NET with asynchronous communication
Apart from exchanging scalar data types with the server, Ajax.NET also supports more complex data types, objects, even images. To give you a sense of what the library can do with more complex data, we will use a database query, return a dataset, and then access it on the client side to fill a list. We start off by querying the database. Again, the Ajax.AjaxMethod() attribute ensures that the returned data will be available on the client side, as well: [Ajax.AjaxMethod()] public DataSet loadVendors() { SqlConnection conn = new SqlConnection( "server=(local)\\SQLEXPRESS; Integrated Security=true; Initial Catalog=AdventureWorks"); conn.Open(); SqlCommand comm = new SqlCommand( "SELECT VendorID, Name FROM Purchasing.Vendor", conn); SqlDataAdapter adap = new SqlDataAdapter(comm); DataSet ds = new DataSet(); adap.Fill(ds); return ds; } Using client-side JavaScript, this method will be called later: function loadVendors() { AjaxNETExample.loadVendors(callComplete); } To output the dataset, an HTML selection list (<select> element) is created. At first it's empty, but it will be filled later on. <select name="vendors"></select> An HTML button will trigger the whole process: <input type="button" value="Load Vendors" onclick="loadVendors();" /> All that remains is the callback function, once again called callComplete(). The code in the callComplete() method loops through the dataset returned from the server. With each iteration, a new list option is generated in JavaScript code and added to the list. The syntax for creating a new list option is as follows: var op = new Option(<name>, <value>); The name of the option is the caption within the list, the value (which is not required) is the information that will be transferred to the server when the form is submitted via GET or POST. Using this knowledge, you can write JavaScript like the following to populate the list with the dataset: function callComplete(result) { var ds = result.value; for (var i=0; i < ds.Tables[0].Rows.length; i++) { var op = new Option( ds.Tables[0].Rows[i].Name, ds.Tables[0].Rows[i].VendorID); document.forms[0].elements["vendors"].options[i] = op; } } You can try to pretty up the code furtherfor instance, by making the button vanish after the list has been filled, or by using proper error handling when the dataset cannot be created. But for demonstration purposes, this example serves well. Example 16-5 shows the complete code. Example 16-5. Using a dataset on the client side
Figure 16-4 shows the result of loading the page and pressing the Load Vendors button. Figure 16-4. The data in the list comes dynamically from the server |