ASP.NET Ajax Web Service

Published: 9/17/2007
By: Kazi Manzur Rashid

Sharing some of the Common Issues of ASP.NET Ajax Web Services.

Introduction

In this article, I will answer some of the common questions which most of the developers face while working with ASP.NET Ajax Web Services.

Basic Call

The first thing I would like to cover is the complete signature of the Web Service method call. Certainly, there are many references available including the ASP.NET Ajax Documentation; but none of them highlighted it.

As you can see, you can pass any contextual data when calling a Web Method. This contextual data along with the method name is available in both Success and Failure callbacks. This extra data becomes handy when you use the same callback function for multiple web methods.

Consider the following example: I have a single callback function, which is used to update the different parts of the same page.

Certainly, you can use the set_defaultSucceededCallback and set_defaultFailedCallback instead of specifying the same callback repeatedly. Note that methodName is the Web Service method name. You can pass anything as the userContext parameter; but it will never be passed to the web method.

The next issue I would like to cover is handling the timeout of a Web Service method call. In the early days of ASP.NET Ajax, there was a separate callback function to handle the timeout. With the final release, a timeout is handled in the failedCallback, like so:

You can use the set_timout of your Web Service class to increase the default timeout value. If you want to increase all of your Web Services timeouts, then use Sys.Net.WebRequestManager.set_defaultTimeout(). This will also change the default timeout value of all your Ajax operations, including the UpdatePanel and manual invoking of Sys.Net.WebRequest.

Complex Data Type Interchange

In this section, I will show you how to implement some complex data types interchange with Web Services. Let's begin with arrays.

The above method is called as follows:

Now, let's see how to do the opposite: Pass an array to a web method.

We can pass the names array like so:

Next, we will see how to pass and return a Dictionary object. Some of you might argue that having a Dictionary object in the method signature always returns a serialization exception in regular Web Services. The ASP.NET Ajax framework allows a Dictionary object in the method signature. Consider the following example, which returns the weathers of different cities of Bangladesh:

We can call this method and format the result as follows:

Let's see how to pass a dictionary to a web method.

We can pass the weathers to the above web methods like the following:

Serializing a complete Object Graph

In this section we will see how to return/pass a custom class using Web Services. By default, the ASP.NET Ajax Framework only generates top-level classes in the Web Service proxy. Consider the following web method:

If you call this method like the following, you will get a JavaScript error saying that Address is undefined:

Since Address is a child object of the Customer class, the framework does not include it in the client proxy. To resolve this issue, add the GenerateScriptType attribute either in the web method or in the Web Service class:

Now you will be able to use the previously shown JavaScript code without any errors. The same holds true for enumerations. This issue has also been discussed by Dan Wahlin in this article.

Exclude Serialization

By default the ASP.NET Ajax Framework serializes all the public fields and properties of custom classes in the client proxy. Sometimes we want to exclude a few of the public fields/properties of those custom classes. To do that, use the ScriptIgnore attribute:

However, this will not have any effect if your web method response format is set to xml instead of default json. In the former case, use the XmlIgnore attribute like you do for regular Web Services.

Serialize incompatible types

The built-in JavaScriptSerializer class of the ASP.NET Ajax framework cannot serialize all the .NET types. Consider the following Employee class; if you try to return it from a web method, you will get a circular reference exception.

In situation like these, the JavaScriptConverter class comes into action. You can write your own custom converters, which transforms the incompatible types to compatible ones for the JavaScriptSerializer class. JavaScriptConverter is an abstract class which has the following signature:

Overriding the SupportedTypes property is mandatory. It instructs the ASP.NET Ajax Framework about the type the converter is responsible for, as in the following example:

If you are both accepting and returning the type, you will need to override both the getter and the setter. In our case we are only returning the Employee; thus we need to override the Serialize method and leave the others without any implementation, like so:

The Serialize method is simply streamlining the hierarchical employee in a dictionary object. To ensure the converter is called when the employee object is serialized you have to register it in the web.config file:

You can have anything for the name but the type attribute needs to be mapped to the type of the custom converter. Once you are done you can obtain the following output with few lines of JavaScript code.

Figure 1: Output obtained using a custom ASP.NET Ajax converter

JavaScriptConverter.jpg

Long Running Web Service Call

In this section I will show you how to display a progress indicator for a long running task, like the one shown in figure 2.

Figure 2: A progress indicator for a long running task

ProgressIndicator.jpg

The design is very simple. First, we invoke a web method, which will start the lengthy task. It will create a status object that contains the progress information, which we will store in the ASP.NET cache. Next, we poll the task status by invoking another web method. Finally, we update the progress bar based upon the task progress. Let's take a peek at the Web Service code.

As you can see, we created the task ID based upon the user name to store it in the cache. Then we are doing some fake delay to simulate a real task and increasing the progress. Note that we cannot use the ASP.NET session, as the session access is always sequential. In the GetTaskStatus method we are simply returning the status from the cache. Now let's examine the client side code.

We are first doing some UI initialization and starting the lengthy task. Then we create a timer by calling setInterval, which polls the task status at two seconds interval. Once we get the status, we check whether the task is complete. If it isn't, we update the progress bar based upon its progress.

Soap Header

It is quite common to add AJAX support for our existing SOAP Web Service. Unfortunately the built-in WebServiceProxy class does not support either the SOAP header or any custom HTTP header. I've developed a custom proxy which has built-in support for both. Consider the following Web Service:

You will be able to call this method with the following code:

Now let see how to pass a custom HTTP header with the new proxy. Consider the following web method:

You will be calling the above method with the following code:

The main issue is that you have to manually write the proxy class for the Web Service. Also, the return type is always XML instead of a JSON object. The following code shows the web proxy for the above Web Service:

You can also use the above proxy for old versions of ASP.NET projects with ASP.NET Ajax Client Library.

Summary

All the above issues are based on feedback from the ASP.NET Ajax WebService Forum. If you experienced any issues that I have missed, please let me know and I will cover it in the future. 

Please visit the link at the below url for any additional user comments.

Original Url: http://dotnetslackers.com/columns/ajax/ASPNETAjaxWebService.aspx