What developer wants to spend hours manually writing Ajax plumbing when the Ajax.NET framework does this for free?
The Ajax.NET Framework presents a remarkably easy-to-use framework that will simplify Ajax development and allow developers to spend more time on implementation details and less time on parsing XML.
What Is Ajax?
If Ajax is still a new concept for you, Ajax stands for Asynchronous JavaScript and XML. Ajax groups these technologies and provides a break from the traditional model requiring a post back to the server in order to run server-side methods. Ajax allows a browser to make calls to server-side code and receive a response from the server all without using the ASP.NET postback, which transfers full ViewState and page information with each request.
How Does Ajax Work?
The “magic” of Ajax lies in the use of the HttpRequest object to facilitate communication between the browser and the server. This object will contact the server, call the designated code and wait for a response from the server. The nice part about this system is that since the processing is asynchronous, the Web browser will continue to allow the user to keep working uninterrupted with the Web application all while continuing to process on the server.
Even with a few extra server calls you are still sending less data across the wire than you would with traditional postbacks which often include full ViewState information.
A very simplistic way to think about this technology is to say that in one respect Ajax grants the user the ability to call code-behind methods from JavaScript.
Call Backs
Ajax will request a service from the server and wait for a response. The way Ajax applications wait for the response is what makes the applications useful. Once you have sent the request to the server for processing, the browser will continue to do its work. Once the server generates a response the browser will recognize that response and then continue processing.
You have two options available to you when calling code on the server in an Ajax environment. You may choose to define a callback method or you may choose to simply send a message to the server and allow the application to continue with its work without being notified the operation is complete.
If you choose to recognize the response, you will define a callback method in JavaScript. A callback method runs once the browser has recognized a response from the server. Once the callback method is invoked, the application may now conduct some additional processing of the response data as provided by the server.
Implications of N-Tiered Development
Some of the traditional lines of n-tier application architecture may blur when you use Ajax. In an application where you use Ajax but you haven’t thought through the architecture, you might have a considerable amount of overlap of business logic in the user interface layer.
You want to make sure you keep your architect’s hat on while developing Ajax applications. Remember that the business layer should know nothing of how to display information to the user and the user interface should not contain business rules. To accomplish this goal, you should strictly return data to the user interface layer and allow UI services to format the data for the final presentation. An Ajax developer may need to use an interim layer between the business objects and the browser to further prepare server-side data before rendering to the browser.
What Is the Ajax.NET Framework?
The Ajax.NET Framework lies on top of the .NET Framework and abstracts the plumbing for Ajax interaction between the server and browser. What is the difference between Ajax and the Ajax.NET Framework? Ajax.NET is a framework around the technologies that create the Ajax method. Without such a framework you must manually code the client/server communication, which is both error-prone and time consuming.
The Ajax.NET Framework dynamically creates proxy objects that act as the communication mechanism between the browser and server. When a developer creates a method in code behind, that method may be decorated with an attribute to tell the Ajax.NET engine to create the necessary JavaScript proxy.
The JavaScript proxy object will have a similar interface to the object as it exists on the server. Using the Ajax.NET Framework, client-side objects will have the same properties as the server-side counterpart. Object methods, however, will not translate from the server side to the proxy object. The proxy is simply a data transfer object and cannot implement server-side logic.
A Basic Example
The following steps will guide you through creating your first Ajax.NET Framework application. While this example may seem basic in nature, it highlights the necessary steps to get your site up and running with the framework.
Hello World Application
The first example will implement a simplistic “Hello World” application. To begin, you may choose to download the sample code from the Web at: http://polymorphicpodcast.com/articles/ajaxnet/helloworld.zip.
If you have yet to download the Ajax.NET Framework, please download it now at: http://ajax.schwarz-interactive.de/csharpsample/. Download the package and extract the contents into a folder that you can easily access.
The final product of this first sample will feature a link that uses the Ajax.NET Framework to retrieve a message from the server. This message is sent to a JavaScript alert box to notify the user. Figure 1 displays what the message will look like.
Step 1: Create a Web Project and Reference Ajax.DLL
First, you must create a new Web project in Visual Studio 2003 to host your application. In your new project, right-click on References and select Add Reference. Navigate to the Ajax.dll file and set a reference in your project to the Ajax.NET Framework.
Step 2: Add the HttpHandler in web.config
Next update your web.config with a new HttpHandler. Adding this handler will allow requests sent back to the application to be interrogated to see if they are designated as “Ajax.NET” requests. If the requests require processing from the Ajax.NET Framework, the request is caught at this step and processed by the framework.
You can easily add the entry to your web.config using the following code snippet. The httpHandlers node is placed directly after the opening of the system.web node.
<system.web>
<httpHandlers>
<add verb="POST,GET"
path="ajax/*.ashx" type="Ajax.
PageHandlerFactory, Ajax" />
</httpHandlers>
...
</system.web>
Step 3: Register Page as an “Ajax Type”
The next step will signal to the application that the individual page you are working on must be processed through the Ajax.NET Framework. In the Page_Load event method you will add the following code.
public class WebForm1 :
System.Web.UI.Page
{
private void Page_Load(object
sender, System.EventArgs e)
{
Ajax.Utility.RegisterTypeForAjax
(typeof(WebForm1));
}
}
In this instance the class name is WebForm1. Notice that you pass in the class name of the page to the method RegisterTypeForAjax using the typeof method.
Step 4: Create your Method and Decorate it with the AjaxMethod Attribute
Next, create a method that will return data to the browser.
[Ajax.AjaxMethod()]
public string SayHi()
{
return "Hello World!";
}
Notice the use of the Ajax.AjaxMethod attribute. Applying the attribute to this method will signal to the application that the appropriate JavaScript must be created to allow client-side calls of this method. Other than the attribute, this method is structured and behaves just as any other method you would normally create.
Step 5: Create your HTML to Call the Code-behind Method
Create some HTML that allows the user to initiate the call to the server. This code will render a link on the page. When the user clicks this link, the browser will contact the server and run the SayHi method. This example defines a callback method so when a response is sent back from the server, the SayHi_CallBack method runs. The SayHi_CallBack defines a response argument. The value of this response is sent to a JavaScript alert box to send a message to the user.
Add the code in the following snippet somewhere between the BODY tags in your HTML document.
<a href="javascript:void(0);"
onclick=
"WebForm1.SayHi(SayHi_CallBack);
">Click Here</a>
Make sure to not include the parenthesis at the end of the method name when defining your call back in the originating method. Add the code in the following snippet within the HEAD tag of your document.
...
<head>
<script type="text/javascript">
function SayHi_CallBack(response)
{
alert(response.value);
}
</script>
</head>
...
How Does this All Work?
When the page is rendered to the browser, a number of JavaScript elements are dynamically created to support the page. When the page is rendered the references to the Ajax.NET JavaScript library files are automatically added to the page. Also created at this time is a JavaScript proxy that acts as the data transfer object between the client and server.
When a user clicks the “Click Here” link, the designated method is called on the server. The server does its processing and then flags the system that a response is ready. When the browser recognizes a response from the server, the callback method is invoked and the response (with the interface of the proxy) is passed as an argument.
In this case, the code behind method SayHi returns a string so the proxy’s value property is simply the string value returned by the method.
The Task System
Now that you have seen a simple implementation of the framework, I’d like to show you an application with real-world relevance. The next set of instructions will guide you through creating a simple task system that will help someone keep track of a to-do list. The application in this article will allow a user to add, edit, and delete tasks.
Figure 2 shows a screen shot of the final product in read mode.
Figure 3 shows the application in edit mode.
Download the code at http://polymorphicpodcast.com/articles/ajaxnet/tasks.zip
This article will discuss all of the functional code needed to make this application work. You will see screen shots of the project that have Cascading Style Sheet entries applied to them giving the screens a styled layout. The CSS used in this application is out of the scope of this article and therefore I won’t discuss it here. If you would like to code this application from scratch using the article, please feel free, but I highly recommend that you at least retrieve the default.aspx.css file from the download package to help give your page an appropriate look and feel.
Description
The task system is simple. When the page loads, a populated instance of the TaskCollection class is returned to the browser. The client will then iterate through the collection and build up some HTML to display each item.
When a user clicks the edit link, the information about the selected task is filled into the controls that make up the edit box allowing the user to update the task information. When the user clicks the save link, the updated information is sent back to the server to update the data store and then the client is updated.
For demonstration purposes, I’ve added a five-second delay to the add and edit features to allow you to see how you may continue to work with the application even if a lengthy server-side operation is in progress.
The data container for this article is a custom class called Task. I’ve packaged multiple tasks into the TaskCollection class. This article uses custom classes and collections to show that you may use your custom business entity classes natively while using the Ajax.NET Framework.
This sample application creates a way to fake a persistence medium. Rather than worrying about the implementation details of dealing with a database or the file system, an instance of TaskCollection is placed into the Application state object. This will act as a stand-in for any sort of persistence medium. When you implement your applications you may follow the same techniques as outlined here, but instead of reading and writing to the Application state object, you may interact with the persistence medium of your choice.
Now that you have that background under your belt, I’ll show you how to implement the application.
Application Configuration
Start with a fresh ASP.NET Web application by creating a new Web project in Visual Studio .NET 2003. Call this project AjaxNET.
Following the steps described above in the Hello World application, add a reference to the Ajax.dll file. Next, update web.config with the Ajax.NET HttpHandler.
<system.web>
<httpHandlers>
<add verb="POST,GET"
path="ajax/*.ashx"
type="Ajax.PageHandlerFactory,
Ajax" />
</httpHandlers>
...
</system.web>
Now delete WebForm1.aspx and create a new Web Form and name the file default.aspx.
Next, in your AjaxNET project add a new folder called Components. This folder will house some of the application’s supporting classes.
Create the Entity and Collection Classes
Add a new class to the Components folder and name the file Task.cs. Listing 1 defines the Task class which is the foundation of the application. The Task class will keep track of three pieces of information: ID, the description, and task title. The only behavior in the class right now is a constructor that will request the description and title. Task ID’s are generated by the constructor when the object is created.
Notice that this class is decorated with the Serializable attribute. Applying this attribute will allow the .NET Framework to serialize a class instance for transport through the Ajax.NET Framework. You must apply this attribute to your custom classes.
The next class to create will fill the role of holding a collection of Task objects. The TaskCollection class, implemented in Listing 2, is a custom collection object that is sub-classed from CollectionBase. This class will begin with two methods. Each method will ensure type safety by taking instances of the Task class as arguments to add and remove items from the collection.
Create the Application Configuration Class
Add a new item in the Components folder and name the file WebAppConfig.cs. Fill out the class as shown in Listing 3.
The WebAppConfig class will provide a holder for the TaskCollection. When the application first accesses the Tasks property, if a collection of tasks does not exist, the property will call a method to create the collection the first time it’s needed. As described previously, to keep this demonstration simple, this class will use the Application state object as a mock persistence medium for the application.
Update default.aspx
Next you need to update the default.aspx page and register the page class for the Ajax.NET Framework. To register the page, add the following code to your Page_Load event.
private void Page_Load(object sender,
System.EventArgs e)
{
Ajax.Utility.RegisterTypeForAjax
(typeof(_default));
}
Note: In C# the word default is a reserved keyword. Visual Studio .NET side-steps any possible confusions of whether your code intends to use your page named default or the reserved keyword by prefixing the type name with an underscore.
Implement GetTasks Method
The GetTasks method will simply return the value of the Tasks property in the WebAppConfig class. Remember that the implementation of Tasks in WebAppConfig will build the task collection if it does not exist.
Be sure to add the using statement at the top of the code behind page so the compiler will know where the WebAppConfig class resides.
using AjaxNET.Components;
Add the GetTasks method and include the AjaxMethod attribute.
[Ajax.AjaxMethod()]
public TaskCollection GetTasks()
{
return WebAppConfig.Tasks;
}
Edit the HTML
When you created the default.aspx page, Visual Studio generated some HTML from a template to create a stub for your page. You will need to add references in the HEAD section of the documents to the following items:
- Style Sheet: As stated above, this article will not detail the styles used in this application, but you may download the default.aspx.css file in the download package at http://polymorphicpodcast.com/articles/ajaxnet/tasks.zip.
- JavaScript: You will create the JavaScript file noted in this listing in the next section. This file will contain all the custom JavaScript for this page.
<html>
<head>
<link rel="stylesheet"
type="text/css"
href="default.aspx.css" >
<script src="default.aspx.js"
type="text/javascript"></script>
</head>
<body>
<form id="Form1" method="post"
runat="server">
<h1>Tasks</h1>
<div id="divTasks"></div>
</form>
</body>
</html>
There are two other elements added to the page. The H1 tag marks up the page heading, making the page’s purpose obvious to the user. The DIV identified as divTasks is a placeholder for the markup dynamically generated by the application.
Next, add a file named default.aspx.js in the same location as the default.aspx file and add the code in Listing 4.
Let’s take a look at this code block piece by piece. The first line assigns the Window_Load method to the onload event of the browser window. Often developers will choose to wire-up this event with the onload attribute of the BODY tag in the HTML. The method you see here is preferable as now all the control of the behavior of the page is controlled within this JavaScript file. Please note the assignment of the method to the event does not include the open and close parenthesis you would normally use with a method call.
The GetTasks method calls the proxy generated by the Ajax.NET Framework calling the server-side method of GetTasks. The implementation seen here will also direct the browser to call the GetTasks_CallBack method when it recognizes a response from the server.
The GetTasks_CallBack method simply calls a function that will do all the work to take the collection of tasks returned from the server and wrap the data with presentation markup to display to the user.
The LoadTasks method looks a bit convoluted at first glance, but the operation is quite simple. This method has a template defined of how to display the task. This template is used in the loop to inject the task information from each item in the task collection.
The last step is to identify the container on the page and set the innerHTML property equal to the string of HTML just built up to display the tasks.
Now when you run the page, you should have a page that displays the tasks on the screen. Your page should look something like Figure 4.
Implement Edit and Delete Buttons
If you recall from Figure 2, the screen shot of the finished product, each task has two buttons associated with its region. The next steps will guide you through adding the edit and delete buttons in each task section.
First you’ll need to update the template in the LoadTasks method. To update the template you will change two areas of the function: you’ll update the template itself and you’ll update the loop that places the task information into the template. Listing 5 shows the changes in the LoadTasks method in bold.
If you look carefully at the change in the for loop, you will notice what may appear to be a mistake. The function executes the exact same line of code in direct succession. This is not a mistake and necessary to get the desired result.
The replace method of the JavaScript string object will replace the first match of its search pattern and then cease execution. The template contains two TASK_ID tokens, one for the edit button and the other for the delete button. Running this line of code twice will replace the token for the desired value in all needed spots.
Implement Control Behavior
The last section directed you to update the template used to load the tasks. In this template the edit and delete buttons call methods that do not yet exist in your application. The next steps will guide you to fill in the blanks.
When the user clicks the edit button, the system will present a task editor “dialog box” granting the ability for the user to change the title and description of the task. The save and close command buttons will appear at the bottom of this box.
The edit task feature must identify on the server which task the user is updating. The client-side knows the task’s Id value so it needs a method that locates a task by its Id value.
Update the TaskCollection Class
The GetTaskById method, implemented in Listing 6, takes a string of the GUID value of the task ID as its only argument. The method will then loop through the collection until it finds a match in the collection. If it finds a match it returns the task object, otherwise the method returns null.
Update default.aspx Code Behind
Now you must update the default.aspx page to use the new method in TaskCollection. The GetTaskById, implemented in Listing 7, will simply pass the task ID into the method of the same name in the TaskCollection class. The result is then returned to the browser.
The DeleteTask method, also implemented in Listing 7, will use TaskCollection’s GetTaskById method to find the task to be removed and then pass that task object into the collection’s Remove method. Finally the DeleteTask method returns the update collection to tasks to the client.
Update default.aspx HTML
The next block of HTML will build the task editor and status message the user will see when they click the add or edit links.
Add the following HTML to the page directly after the <div id="divTasks"></div> element on the page.
<div id="divTaskInput">
<h3>Task Editor</h3>
<input type="hidden" id="hdnId"
name="hdnId" />
<h4>Title</h4>
<asp:textbox id="txtTitle"
runat="server" />
<h4>Description</h4>
<asp:textbox id="txtDescription"
textmode="MultiLine"
runat="server" />
<div class="submit">
<input id="btnSave"
name="btnSave"
onclick="btnSave_Click();"
type="button" value="Save" />
<input type="button"
id="btnClose" name="btnClose"
value="Close"
onclick="btnClose_Click();"/>
</div>
</div>
<div id="divStatus">Saving...</div>
The first part of this listing shows opening a DIV tag identified as divTaskInput. This will act as a container for the section.
The hidden input field holds the task’s ID. The value of the ID is not necessary to display to the user, so it’s placed in a hidden input control.
The rest of the markup defines the input controls needed to allow the user to edit the title and description of the task. This code wires-up the HTML to JavaScript that you will add in coming sections.
Finally, the DIV identified as divStatus is a container for a status message that gets displayed to the user during server-side latency. The container is hidden by default in the referenced CSS file and only shown to the user when the browser is waiting for a response from the server.
Update JavaScript
There is a function that implements some common operations the application will often use. The IsValidResponse function, implemented in Listing 8, will interrogate a response from the server and decide if the response is useable by a callback function.
This function will make sure the response and its contained value are valid. If it finds a valid state, the function will return true. If the response is invalid somehow, or there was an exception thrown on the server, the function will return false. In the case of an exception, the response includes an error object and the exception information may be displayed to the user.
Add Element Methods
Element methods are JavaScript functions that are meant to act much like protected member variables in an ASP.NET page. These functions act as a wrapper to the input control or element on the page so you only have to find the control on the page once. Often you will see code littered with unnecessary uses of the document.getElementById method. Using element methods will clean up your code and help you avoid redundancy. Listing 9 shows an example of how to use these functions.
Create an element method for each of the controls you will access on the page. Notice, just as in the standard .NET code behind variables, you’ll name your element methods the same as the element ID defined in the HTML.
Add Behavior Methods
The next set of functions you will add perform the work of finding the tasks and either updating or deleting the objects from the collection. These functions are responsible for using the functions I created in the code behind in Listing 9.
The GetTaskById function, implemented in Listing 10, passes in the task ID to the server-side method of the same name. Once the client recognizes a response, it calls the GetTaskById_CallBack function.
The GetTaskById_CallBack function first uses the IsValidResponse utility method to ensure a valid response from the server. If the server sends the expected response, the requested ID, title, and description are placed into the value properties of the input control objects by this function. If the task is not found, the user is notified via a JavaScript alert.
The DeleteTask method takes the Task ID as the only argument. This method will then contact the server and run the implementation for DeleteTask server-side. Remember that the server will return the updated collection when an item is deleted from the list. With the collection returned from the server, you do not need to write any additional code to finish this process-all you need to do is to display the task information to the user. The GetTasks_CallBack method works perfectly in this instance. GetTasks_CallBack will pass the response to the LoadTasks which will apply the template to each task item and display the update list to the user.
function DeleteTask(id)
{
_default.DeleteTask(id,DeleteTask_Call
Back);
}
function DeleteTask_CallBack(response)
{
GetTasks_CallBack(response);
divTaskInput().style.display =
"none";
}
EditTask calls the GetTaskById method you already implemented. This will find the task and display the values in the input controls on the page. Next the input box is displayed to the user by setting the DIV’s display property off the style object equal to block, thus showing the box to the user. Finally, the method sets focus to the title control to make editing the task easy for the user.
function EditTask(id)
{
GetTaskById(id);
divTaskInput().style.display =
"block";
txtTitle().focus();
}
Now when you run the page you will see an edit link and a delete link. If you click the delete link, the task item is successfully deleted from the list and the page is updated. If you click on the edit link, an input box will appear with the task information populated in the input controls. The Save and Close buttons are not yet implemented, so clicking on those buttons at this time will result in JavaScript errors.
Implement the Task Editor Controls
Now you must implement the behavior that will send changes to the server to update the collection store.
The following instructions will direct you to implement the Save and Close buttons in the task editor. The last feature you’ll add to the application is the ability to add a task. The following code will implement some of this logic as the Save method is concerned with saving task data whether or not it is a new task or an update to a task.
Update TaskCollection Class
Adding the UpdateTask method, implemented in Listing 11, requires the task ID, the update title value, and the updated description value as arguments. Once the desired task is located in the collection the updates are made to the title and description.
If the task is found the method returns true, if the task is not in the list the method returns false.
Update _default Class
Adding the EditTask method requires the task ID, title, and description as arguments. Please notice that I put the call to System.Threading.Thread.Sleep(5000) in this method simply for demonstration purposes. Calling the Sleep method will force the application to wait for five seconds before continuing on with its processing. This simulates a long server-side transaction and shows how the browser can deal with that type of latency. Finally, the data received by the page is passed to the Task object to update the task.
[Ajax.AjaxMethod()]
public bool EditTask(string id, string
title, string description)
{
// The following line is for
// demo purposes only
System.Threading.Thread.Sleep(5000);
Guid gId;
gId = new Guid(id);
return WebAppConfig.Tasks.UpdateTask(gId,
title,description);
}
The AddTask method creates a new task object from the passed in title and description and then adds the new object to the task collection.
[Ajax.AjaxMethod()]
public bool AddTask(string title,
string description)
{
// The following line is for demo
// purposes only
System.Threading.Thread.Sleep(5000);
Task task;
task = new
Task(title,description);
WebAppConfig.Tasks.Add(task);
return true;
}
Update JavaScript
Remember that the Save button persists task information on the server whether or not a task is new or recently edited. The order of business is to decide if the task is new or if the user clicked the edit link.
When the edit link is clicked the task information is queried on the server and the values are filled in the input controls.
The btnSave_Click method, implemented in Listing 12, will handle the logic to save task information on the server. If the task ID hidden control has a value, then the application knows that it’s dealing with an existing task. The EditTask method on the server is then called, passing in the task ID and the updated title and description. The final argument directs the browser to call EditTask_CallBack when it recognizes a response from the server.
The EditTask_CallBack method will check for a valid response, hide the status message, and then load the updated task collection on to the page.
If the page determines the task is new, it calls the AddTask method on the server. Once the client receives a response from the server the EditTask_CallBack method is also called for this operation.
Finally, the btnSave_Click method, implemented in Listing 12, will update the user interface to hide the task editor and show the status message on the screen. The callback methods hide the status message when the server operation is complete.
The EditTask_CallBack method will look for a valid response. If everything went as planned, the status message is hidden and the browser is directed to display the updated task collection to the user.
function EditTask_CallBack(response)
{
if(IsValidResponseValue(response))
Then {
divStatus().style.display =
"none";
GetTasks();
}
}
The btnClose_Click method simply hides the task editor from the user.
function btnClose_Click()
{
divTaskInput().style.display =
"none";
}
Now when the user clicks the Edit button the task editor will appear. When they click the Save button, a status message appears at the bottom of the browser window which will persist until the client hears back from the server indicating the process is complete. Figure 5 shows how the status message will appear at the bottom of the browser window.
The application can now display the tasks to the user and allow the user to edit and delete tasks. The system is missing one last feature. The next section will grant the user the ability to add a new task to the list.
Implement Add Task
At this point you’ve written most of the code necessary to make the application work. Adding the add task feature from here is easy.
First you want to update the HTML document. Return to default.aspx, switch to the HTML view, and make the following changes to the file.
Update default.aspx
The HTML requires adding a link to the page that will tell the application you are creating a new task and then display the task editor to the user.
Locate the point in the file where the H1 and the DIV identified as divTasks meet. Place the new line of code shown in the below snippet between these two lines.
<h1>Tasks</h1>
<a href="javascript:void(0);"
id="lnkAdd" name="lnkAdd"
onclick="lnkAdd_Click();">Add Task</a>
<div id="divTasks"></div>
The addition of this anchor tag will display an Add Task button to the page and direct the browser to call lnkAdd_Click when anyone clicks the link.
Update the JavaScript
The ClearTaskInput method will clear the controls in the task editor, priming the system for a new task.
function ClearTaskInput()
{
hdnId().value = "";
txtTitle().value = "";
txtDescription().value = "";
}
The btnAdd_Click method will clear the task editor of any previous values, display the task editor to the user, and set focus to the title control.
function lnkAdd_Click()
{
ClearTaskInput();
divTaskInput().style.display =
"block";
txtTitle().focus();
}
You now have a fully functioning task system using the Ajax.NET Framework.
Conclusion
Now that you have had an opportunity to use the Ajax.NET Framework you’ll notice that there are a few steps in traditional Ajax development that are unnecessary. When a response is returned from the server you have a response object filled with the returned data. At no time did you have to parse through XML markup or manually poll the server for ready states. The Ajax.NET Framework saves developers time and simplifies the process of creating Ajax applications.