Home  |  Software  |   Forum  |  Download  |  Sitemap  |  Make a Donatation  |  Cafe   |  Press

Clipper Software

ARI - Asynchronous Remote Interface (Ajax)

At a Glance

What is ARI? A .NET Ajax library for Microsoft .NET websites.
Current Version 1.0
Requirements IIS 6.0 or later; ASP.NET 2.0 or later;
Usage ASP.NET Websites

Quick Links:  Download  |  Example Code  |  Donate

Overview

To be clear, ARI is a .NET Ajax library. But it is way different than most of the other libraries available. It is super easy to use, but oh so powerful. Don't be fooled by the simple interface. There is a freakin lot going on underneath the hood. ARI is the coolest and most useful and time-saving component I have developed.

How ARI Works

ARI implements the IHttpHandler interface, called the ServiceBroker. It is the gateway between your web page and the web server. In order to route calls to the ServiceBroker, you need to add the following code snippet to your web.config file. It must be within the system.web tags. This tells the IIS server that any requests made to ARIRemoteServices.axd should go to the ARI ServiceBroker.

Add this to your web.config

The only required configuration for you to do is to add a "whitelist" of methods that you want to allow to be called from the web browser. The previous version of ARI used to use .Net reflection to enumerate all the methods in the App_Code directory, but I got enough requests to change that since it there was no way to limit what could be called from the browser. The current version requires an explicit white list in the AsyncRemoteInterface.dll.config file. I felt adding a method list here was much cleaner than having to clutter up the actual source code with a combination of using statements and method attibutes. In any event, when ARI is first loaded, this list of methods is read and cached, and remains cached until IIS or the web site is recycled. Below is the actual method whitelist from the config file that comes as part of the example web site when you download ARI. [More on the configuration file later.]

The config file that comes as part of the example web site

The next thing to do is to add the following line to the top of any web page you want to make Ajax calls from.

Add this in the head section of your web page

Because of the line you added in the web.config file, this call is routed to the ARI ServiceBroker. The ServiceBroker sees that this call is from a web page, and responds with two critical items. First is the JavaScript client code, which is what allows you to make the Ajax calls in the first place. This code is always the same. (More on this code in a second.) The second thing that gets returned is a set of dynamically generated JavaScript methods that enable you to interact with your server code so easily. For every distinct class and method, a JavaScript object and method is created. For overloaded methods in the same C# class, just one JavaScript method is sufficient. Because of this dynamic code, you can call your C# methods from JavaScript using the following syntax. The first example call shows a call that does not take any parameters, while the second call shows one that does take parameters.

Example 1
Example 2

How great is that! In the first example, we are calling a C# method called GetSalesTotals, that is a member of a class called Reporting. The first argument ( cb_GetSalesTotals ) to the method is always the callback function that will execute if the call was successful. The second argument ( err_GetSalesTotals ) to the method is the callback function that will be called if there was a problem. This includes exceptions, including those in your server code that you did not have a catch block for. ARI is already picking up your slack! :-)

Note - as a matter of convention, I tend to name my callback functions the same as the server method I am calling, with a prefix of cb_ for the success callback, and err_ for the error callback. It is good practice and keeps the code readable.

Here is where it gets interesting. To start with, ARI implements the complete XmlRpc wire protocol. You would never know it though because that happens in the middle-tier, inside the communications layer. ARI's job is to make your job easier and hide all that complexity from you. Nevertheless, ARI serializes the request as well as the response back for smooth and reliable network communication. At a high level, here is what takes place during an ARI remote Ajax call, using Example 2 above to illustrate:

The dynamic code that was generated and sent to the page invokes the ARI JavaScript client proxy, which hands the request to the XmlRpc serializer.

The data types of any parameters are determined and written to an Xml string according to the XmlRpx specification.

Any string data is base 64 encoded before being added to the outbound Xml. This allows transmission of otherwise illegal characters in Xml, such as greater than, less than, etc.

An ARI internal callback that lives in the JavaScript client is substituted for the callbacks supplied as arguments.

Using a POST method, the asynchronous call is made to the ARI ServiceBroker, sending the serialized data as an Xml string.

The ServiceBroker receives the call, and hands it off to the ServerAgent. The ServerAgent orchestrates the entire server side operation.

The ServerAgent hands the request to an XmlRpc deserializer. The deserializer builds a C# object that includes necessary information such as class name, method name, and the array of arguments. The XmlRpc deserializer also converts the inbound parameters to their native corresponding C# types. These types were indicated in the serialized message. See the XmlRpc spec for complete information. Also note that incoming string data types are base 64 decoded so they can live again in the real world.

Once fully deserialized, the request object is handed off to the Executive. This class is reponsible for the execution of the intended server side method. Using the Microsoft reflection API, a call to the class and method having the name specified in the request is invoked. The reflection API determines the correct match in the event of method overloading. You should be aware that you may receive an exception indicating that the method does not exist. That isn't exactly the case. The problem is that a method with the implied signature does not exist. Let's say you have a method that takes an integer as its one and only argument. Now let's say you invoked the method from JavaScript and passed in 22.78 as the argument. If ARI were to actually make the call to the C# method, narrowing coercion takes place and the fraction portion of the argument would be lost. Of course, this is not acceptable, so an exception is thrown. Conversely, if the C# method took a float or a double as its one and only parameter, passing an integer would be ok. Widening coercion would take place, thus promoting the integer value to the necessary float or double with no resultant data loss.

If the method has a return type, it is received by the Executive as a result of invoking the method. A response object is created, the result object is placed inside it, and the response object is then handed off to the XmlRpc serializer. Although I will discuss it later, return types are limited to types inherent to the C# language. This should be more than sufficient for just about all your needs. But, ss I said, more on that later. One of the greatest things about the ARI serializers and deserializers, both on the server side in C#, as well as in the JavaScript client, is that they can handle an infinite level of data nesting. For example, a structure can contain other structures, arrays, basic data types, lists, and more. And each of those can contain even more objects, and so on, and so on. For example, let's consider a server side method that returns a DataTable. You can look at a DataTable as an array of structures, right? Each row is a structure, with column names as the name, and the data as the value. The parent array contains all of these structures (rows).

Once serialized, the final Xml is sent back to the ServerAgent, who, in turn, passes it back to the ServiceBroker, where it all began. Up the chain and back down the chain. The ServiceBroker then passes this serialized Xml string back as the response to the original client call.

The response is received by the ARI JavaScript client callback, where it is then handed to the ARI JavaScript deserializer. At this point ARI decides how to map the data type(s) contained in the response message. Although there is only one (or none if the server method has a return type of void) result object, it may contain many objects within itself, whose data type mapping have to be determined and the proper JavaScript data types created.

Almost there. Once the equivalent JavaScript return object is created by the deserializer, it is passed back to the ARI client proxy. If the result object is the result of a successful remote call, the client proxy calls the users success callback, and passes back the result object as an argument. If however an error occurred, the result object is a string describing the error. These errors can occur as a result of a problem in the server method, or in ARI itself, as would be the case if you called a server method with incorrect or missing parameters.

Important Note:

A good programmer is someone who looks both ways before crossing a one-way street.

The JavaScript user callback itself is invoked by the ARI client proxy inside a try-catch block. This is important because an error in the user callback will unwind the stack and cause an error inside ARI, even though the problem is the user callback function code. To protect against this, ARI invokes the user callback code from within a try-catch block. If the user code throws an exception, the response from ARI will be something like Your success callback threw the following exception: bla bla bla, where bla bla bla is the description text of the JavaScript exception. (Bla bla bla is a very technical term you know!)

At that point, the call is complete, and the user has the result of the C# server side method. Life is good!

Data Mapping

Table 1: Sending arguments from a Javascript client to a C# server method.

The column on the left is the datatype of the C# method parameter, and the column on the right is a list of acceptable JavaScript datatypes that can be sent.

C# Datatype Javascript Datatype
string string
bool bool (true | false)
int int (no decimal places)
double, float number with decimal places, int
Array (descendants of IList) Array
Hashtable (descendants of IDictionary) Object
DataTable Array of Objects
 

Table 2: Receiving return values from a C# server method when using a Javascript client.

The column on the left is the return datatype of the C# method, and the column on the right is the Javacript datatype that will be received in the success callback function. (The failure callback function always receives a string datatype.)

C# Datatype Javacript Datatype
string string
bool bool
int int
double, float number with decimal places
Array (descendants of IList) Array
Hashtable (descendants of IDictionary) Object
DataTable Array of Objects
 

ARI Configuration

Except for adding the methods you want to allow to be called from the browser, there is not a lot to configure with ARI. The only option in the AsyncRemoteInterface.dll.config is called packing and controls whether or not the dynamically generated JavaScript methods that are sent to the browser are packed or not. Internally, the generator uses the Dean Edwards JavaScript packing algorithm. The two options for this configuration setting are enabled, which is the default, or disabled.

You can download the library here and examine the code. There are a bunch of examples on the ARI example code page that will help you understand even further. Like I said, ARI is a huge time saver! I just cannot imagine how long some tasks would take or the compromises I would have to make if it weren't for this component. If you are interested in .NET Ajax programming, or have an actual project you need to get done, do yourself a favor and at least check it out.