Few days back one of my of ex-colleague called me to know what is the best platform of Ajax to work in VS2003 Project, One of his client wants to implement some Ajax features in his existing application . Is it Ajax.net, Prototype, jQuery or Dojo? When I replied him Asp.net Ajax 1.0, he seems bit confused. Yes we can also use Asp.net Ajax for the older version of VS. However, we will not get the full set of features in those older environment. Let me list those features, which will not be available:
- Cannot use Server Side Controls such as ScriptManager, UpdatePanel, UpdateProgress, AjaxControlToolkit etc.
- Application Service such as Authentication, Profile will not be available.
- PageMethod will not be available.
- There will be no Client Side Proxy for the WebServices.
- The Data will be always transmitted in Xml not in JSON.
Even those missing features we will still able to use rich set of API which includes:
- Base Type Extension
- Able to Send Request and consume Response to any http endpoint which we see will in later section.
- Able to use Client Side Components, Extenders and Controls.
- All other Client Side Library API except Sys.WebForms
Let us see how to consume a VS2003 Web Service in Asp Ajax Framework. First download the Microsoft AJAX Library which only contains the JavaScript files. Once downloaded add the MicrosoftAjax.js in your Web Project and then your pages where you want to implement Ajax. Next add a Web Service in your Web Project. For shake of the simplicity I will create some basic functions. First create a WebMethod which returns the Server DateTime like the following:
[WebMethod]
public string GetCurrentTime()
{
return DateTime.Now.ToString();
}
Now lets see how to call this WebMethod from the JavaScript.
function getServerTime()
{
var request = new Sys.Net.WebRequest();
request.set_url('SimpleWebService.asmx/GetCurrentTime');
request.set_httpVerb('POST');
request.add_completed(onGetServerTimeComplete);
request.invoke()
$get('divTime').innerHTML = '';
}
function onGetServerTimeComplete(executor, eventArgs)
{
if (executor.get_responseAvailable())
{
$get('divTime').innerHTML = executor.get_xml().documentElement.firstChild.nodeValue;
}
}
First we are creating a Sys.WebRequest object and then we are setting the required properties and events such as the end point (The convention is WebServiceUrl/WebMethod), Http Method Post/Get and finally we are binding onComplete Handler. In the onComplete Handler we are getting the response from the WebRequest's Executor xml Property. The Executer is passed in the onComplete Handler and the xml property represents an XML DOM Document. You can get more info on WebRequest and Executor from these links WebRequest and Executor.
In this section we will see how to pass parameters in the WebRequest object when calling a WebMethod, For example if your WebMethod is like this:
[WebMethod]
public bool IsValidEmails(string emails)
{
string[] emailArray = emails.Split(',');
for (int i = 0; i < emailArray.Length; i++)
{
if ((!emailArray[i].Contains("@")) || (!emailArray[i].Contains(".")))
{
return false;
}
}
return true;
}
You can call it in JavaScript like the following:
function isValidEmail()
{
var requestBody = 'emails=' + $get('txtEmails').value;
var request = new Sys.Net.WebRequest();
request.set_url('SimpleWebService.asmx/IsValidEmails');
request.set_httpVerb('POST');
request.set_body(requestBody);
request.get_headers()['Content-Length'] = requestBody.length;
request.add_completed(onIsValidEmailComplete);
request.invoke()
$get('divResult').innerHTML = 'Loading';
}
function onIsValidEmailComplete(executor, eventArgs)
{
if (executor.get_responseAvailable())
{
$get('divResult').innerHTML = executor.get_xml().documentElement.firstChild.nodeValue;
}
}
The only difference this time comparing to first example is we are setting the body of the request where we are are passing the comma separated email addresses. If you have mulitple parameter then append it with & (Ampersand) character in the request body for example param1=value1¶m2=value2 etc.
So far we have seen only intrinsic data type transfer, now lets check how to send and receive complex data types. Lets create a dummy WebMethod which returns an array of Employee object like this:
[WebMethod]
public Employee[] GetEmployees()
{
ArrayList list = new ArrayList();
for (int i = 1; i < 6; i++)
{
Employee emp = new Employee();
emp.Name = string.Format("Employee Name #{0}", i);
emp.Address = string.Format("Employee Address #{0}", i);
emp.Salary = i * 10000;
list.Add(emp);
}
return (Employee[])list.ToArray(typeof(Employee));
}
Now call this WebMethod from JavaScript like this:
function getEmployeeList()
{
var request = new Sys.Net.WebRequest();
request.set_url('SimpleWebService.asmx/GetEmployees');
request.set_httpVerb('POST');
request.add_completed(getEmployeeListComplete);
request.invoke()
$get('divList').innerHTML = 'Loading...';
}
function getEmployeeListComplete(executor, eventArgs)
{
if (executor.get_responseAvailable())
{
var xndEmployees = executor.get_xml().documentElement.getElementsByTagName('Employee');
if (xndEmployees)
{
var output = '';
if (xndEmployees.length > 0)
{
for(var i = 0; i < xndEmployees.length;i++)
{
var emp = new Employee(xndEmployees[i]);
output += emp.Name + ':' + emp.Address + ':' + emp.Salary + '<br/>'
}
}
$get('divList').innerHTML = output;
}
}
}
function Employee(xndEmployee)
{
this.Name = xndEmployee.getElementsByTagName('Name')[0].firstChild.nodeValue;
this.Address = xndEmployee.getElementsByTagName('Address')[0].firstChild.nodeValue;
this.Salary = parseFloat(xndEmployee.getElementsByTagName('Salary')[0].firstChild.nodeValue);
}
The real difference between handling the complex object is that we have to roll our own logic converting to custom object from the xml response like the above.
In this section we will check how to send a complex object in Asp.net Ajax. Lets create another dummy method which takes an employee object and returns a new id for that employee, like this:
[WebMethod]
public int CreateEmployee(Employee employee)
{
//Store it in DB
int id = (new Random()).Next(1000, 10000);
return id;
}
Now lets see how to call this method in JavaScript:
function createEmployee()
{
var requestBody = '<?xml version=\"1.0\" encoding=\"utf-8\"?>' +
'<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">' +
'<soap:Body>' +
'<CreateEmployee xmlns=\"http://tempuri.org/\">' +
'<employee>' +
'<Name>' + 'Joe Doe' + '</Name>' +
'<Address>' + 'Nowhere' + '</Address>' +
'<Salary>' + '25000' + '</Salary>' +
'</employee>' +
'</CreateEmployee>' +
'</soap:Body>' +
'</soap:Envelope>';
var request = new Sys.Net.WebRequest();
request.set_url('SimpleWebService.asmx');
request.set_httpVerb('POST');
request.set_body(requestBody);
request.get_headers()['Content-Length'] = requestBody.length;
request.get_headers()['SOAPAction'] = 'http://tempuri.org/CreateEmployee';
request.get_headers()['Content-Type'] = 'text/xml; charset=utf-8';
request.add_completed(onCreateEmployeeComplete);
request.invoke()
$get('divID').innerHTML = 'Loading..';
}
function onCreateEmployeeComplete(executor, eventArgs)
{
if (executor.get_responseAvailable())
{
var xndResult = executor.get_xml().documentElement.getElementsByTagName('CreateEmployeeResult');
$get('divID').innerHTML = xndResult[0].firstChild.nodeValue;
}
}
As you can see there are quite bit of difference in this case, first we are constructing a Soap Message, next in the url we are not specifying the WebMethod name instead we are specifying the WebMethod name by adding a new header SOAPAction, we are also adding a new header for the request content type which is text/xml.
In conclusion, I would like to say that main advantage of implementing Asp.net Ajax Library in older VS projects is that we can easily employ our existing knowledge of Asp.net Ajax, no need to learn any new framework and later on If we decide to upgrade our project in VS2005 or maybe VS2008 we can easily do that without breaking a single line of code.
Download: Complete Code
