5

Webservices and Javascript

 

Until recently, C# programs were pressed into action to execute the code contained in an asmx file. Since the scales are heavily tilted in favour of scripting languages, we considered it to be much more prudent to develop a convenient method of calling functions remotely, using a scripting language like JavaScript, within an html file.

 

This chapter takes a small breather from the C# language, and immerses itself in the world of JavaScript, which is a scripting language. Javascript in an html file can be used to call functions remotely. The packets that flow to and from IE that loads the html file to the web service, are SOAP-based.

 

Before we embark on our journey, we need to download a file named webservice.htc from the Microsoft site, and place it in the root directory of IIS at C:\inetpub\wwwroot. The URL to download the file is http://msdn.microsoft.com/downloads/samples/internet/behaviors/library/webservice/webservice.htc.

 

This file has a size of 48714 bytes. A file with the htc extension exhibits one of Microsoft's extended support to html files, where it enables you to write code and attach it to an html element. There is no need to decipher the code in this file for the moment. Therefore, let us actually get down to the task of calling code within a webservice named a.asmx, from an html file called a.html. The html file has to be placed in the root directory, i.e. c:\inetpub\wwwroot.

 

a.asmx

<%@ WebService Language="C#" class="zzz" %>

using System;

using System.Web.Services;

public class zzz {

[WebMethod]

public int abc(int i, int j)

{

return i + j;

}

}

 

a.html

<SCRIPT language="JavaScript">

var n = 10;

function init1()

{

s.useService("http://localhost/a.asmx?WSDL","yyy");

s.yyy.callService("abc",22,n);

alert("Over");

}

function aaa()

{

alert(event.result.value);

}

</SCRIPT>

<body onload="init1()">

<input type=text id="s" style="behavior:url(webservice.htc)" onresult="aaa()" />

</body>

 

Output

Messagebox - over

Messagebox - 32

 

Our asmx file is nothing to crow about! It merely contains a simple function abc, which accepts two int values. The values contained in the parameters are added up, and then, the sum is returned back.

The html file is where the real action lies. All script-related code, be it in JavaScript or Visual Basic script, is enclosed within the Script tag. Since we are using JavaScript- the scripting language invented by Netscape, the language attribute is assigned the value of 'JavaScript'. Thereafter, two functions named init1 and aaa are created.

 

In order to create a function in JavaScript, the syntax that is followed is: the word 'function', followed by the 'name of the function', followed by the familiar () and {} braces. This syntax is similar to the one seen in the C# language. Nothing really changes in the world of programming languages after all!

 

There is no dire necessity of creating a variable in JavaScript, but for those who are addicted to the traditional programming paradigm, the word 'var' is to be specified with the name of the variable, which in our case is 'n'. The variable n has been assigned a value of 10. In a scripting language like Java Script, there is no concept of a data type at all. There is no way of specifying the data type of the variable n, because most scripting languages are type-less.

 

Returning to the html file, we stumble upon the familiar html tag called 'body', which has an attribute of 'onload'. Since it is initialized to init1, the function init1 gets executed when the html file is loaded into the browser. Thus, before the user gets control, this function gets called. But, before init1 can be called, the rest of the html file is evaluated. The textbox has an id of 's', and the code in the htc can now be accessed using this identifier. The html tag named 'input' displays a textbox in the browser window. The attribute of 'style' attaches an htc file to the element. Bear in mind that the name of the htc file has to be specified using the specific syntax. There is no necessity of using the 'div' tag, as has been the case in most of the Microsoft examples. Just any element can fit the bill.

 

The attribute of 'onresult' is assigned a function name 'aaa', which shall be called, each time a result is made available from the remote server. This approach eliminates the possibility of an eternal wait while the server processing is in progress, since the server may take inordinately long to accomplish its task of executing a function and returning a value. When the response SOAP packet is received from the server, the function aaa gets called.

Once the html file is rendered, the function init1 gets called. In init1, the first function to be called from the htc file is 'useservice'. You may open the htc file and view this function for your sheer personal satisfaction.

 

The first parameter is the WSDL representation of the asmx file. Hence, the URL is specified as http://localhost/a.asmx?WSDL.

 

Hereinafter, the WSDL file will be identified by the name 'yyy' throughout the rest of the program. This name is in no way related to any name in the asmx file. It is the abstract representation in the WSDL file that is taken into consideration, and not the actual code in the asmx file. You can switch on the SOAP trace utility program and bear witness to the entire wsdl file being received.

 

The second function to be called from the htc file is callService. In order to call this function, a predefined pattern needs to be followed. Here, the id 's' is first specified, followed by the name of the webservice 'yyy', and finally, by the function name 'callService'. Thus, the resultant expression is s.yyy.callService.

 

The parameter supplied to this function, first accepts the function to be called in an asmx file, i.e. abc, followed by the list of parameters to be supplied to abc, viz. 22 and n. The parameters may either be the actual numbers or variables. The 'alert' function containing the text of 'over', displays a message box containing the text 'over'. 

 

On entering the url of http://localhost/a.html in the browser address box, a textbox gets displayed initially, followed by two message boxes:

     The first one with the text of 'over'.

     The second one with the value of 32.

 

Here, we have made an asynchronous call. What it signifies is that, the function 'callService' does not 'block' or 'wait'; it immediately executes the next line of code. Hence, the alert message box gets displayed. If and when, the return SOAP packet arrives, the function aaa is executed, which exhibits the return value of 32. This number 32 is displayed using the value member of the result object in the event object. The sequence of the alerts is of no significance.

 

In the next program, the a.asmx file remains unchanged. In addition to it, another asmx file named b.asmx makes an appearance.

 

b.asmx

<%@ WebService Language="C#" class="zzz" %>

using System;

using System.Web.Services;

public class zzz

{

[WebMethod]

public int pqr(int i, int j)

{

return i * j;

}

}

 

a.html

<SCRIPT language="JavaScript">

var n = 10;

function init1()

{

s.useService("http://localhost/a.asmx?WSDL","yyy");

s.useService("http://localhost/b.asmx?WSDL","xxx");

i = s.yyy.callService("abc",22,n);

j = s.xxx.callService("pqr",122,n);

alert("Over " + i + ' ' + j);

}

function aaa()

{

alert(event.result.value + ' ' + event.result.id);

}

</SCRIPT>

<body onload="init1()">

<input type=text id="s" style="behavior:url(webservice.htc)" onresult="aaa()" />

</body>

 

Output

Messagebox  Over  0 1

Messagebox          32 0

Messagebox          1220 1

 

The function pqr in b.asmx simply multiplies the two parameters passed to it, and returns the result.

 

In the html file, the init1 function assigns the name yyy to the first webservice named a.asmx, and the name xxx to the second web service named b.asmx. A single element, which hereinafter is identified as 's', can be associated with multiple web services.

 

A hiatus at this point is that the function aaa gets called for both invocations of functions abc and pqr, in the two webservices. The question is- how does the system distinguish one web service call from the other? To ascertain this difference, the return value of the callService function is stored in two different variables,  i and j.

 

For the first alert containing the text of 'over', the value of i is zero, and that of j is one. The function aaa, when called, displays the result of the multiplication, which is stored in the value member. It also displays the id member of the result object, which belongs to the event object. Thus, the alert displays the values of 32 0, followed by 1220 1. Therefore, using this method, we can now identify the caller of the callback function aaa.

 

a.html

<SCRIPT language="JavaScript">

function init1()

{

s.useService("http://localhost/a.asmx?WSDL","yyy");

s.yyy.callService("pqr");

}

function aaa() {

a = event.result.errorDetail.code;

b = event.result.errorDetail.string;

c = event.result.errorDetail.raw;

d = event.result.error;

alert(a + ' ' + b + ' ' + c + ' ' + d);

}

</SCRIPT>

<body onload="init1()">

<input type=text id="s" style="behavior:url(webservice.htc)" onresult="aaa()" />

</body>

Message Box

Client Invalid Argument null true

 

In the above html file, we deliberately erred, by requesting the program to execute the function pqr. No function by this name exists in the a.asmx file. In spite of this error, function aaa got called, which then reported the error. The error member in the result object contained the value of true, and the code and string members in the errorDetail displayed the position and the error message, respectively.

 

Thus, any error in the asmx file can easily be brought to light. In case of any error, the errorDetail member contains a non-null value; in the absence of all errors, the error member is false, and the errorDetail member contains a null value. Hence, comprehensive error checks can be performed, based merely on the value contained in this member.

 

a.html

<SCRIPT language="JavaScript">

function init1()

{

s.useService("http://localhost/a.asmx?WSDL","yyy");

s.yyy.callService( bbb, "abc", 10 ,20);

}

function bbb(r)

{

alert(r.value);

}

</SCRIPT>

<body onload="init1()">

<input type=text id="s" style="behavior:url(webservice.htc)" />

</body>

 

MessageBox

30

 

This program evinces the advantages of JavaScript over the C# language. By the way! I am no stranger to the fact that this is a C# book, but nonetheless, there are a few facts that need to be brought to light for your knowledge.

 

Remove the onresult attribute from the input. Then, specify a javascript function named bbb in the callService. Thereafter, follow it up with the parameters, starting with abc, which is the name of the function in the webservice, followed by the parameters to the function. Function bbb now gets called with a parameter 'r', which is the result object. The alert function displays the value contained in the value member, i.e. 30. There isn't much dissimilarity in the two approaches, other than the method used to obtain the result object.

 

a.html

<SCRIPT language="JavaScript">

function init1()

{

var a  = new Object();

a.funcName = "abc";

a.async = true;

a.timeout = 120;

s.useService("http://localhost/a.asmx?WSDL","yyy");

i = s.yyy.callService( bbb , a  , 10 ,20);

alert("hi" + i);

}

function bbb(r)

{

alert( 'bbb' + r.value);

}

function aaa()

{

alert( 'aaa' + event.result.value);

}

</SCRIPT>

<body onload="init1()">

<input type=text id="s" style="behavior:url(webservice.htc)" onresult="aaa()" />

</body>

 

Output

Messagebox hi0

Messagebox bbb30

 

 

In the above html file, the onresult attribute points to the aaa function, which shall be called when a SOAP message arrives. The init1 function creates a new object called 'a', and then initializes the funcName member to abc, which is the function to be called. Thereafter, the async member is set to true, thereby, making the call asynchronous. The 'timeout' determines the waiting period for the arrival of the response packet.

 

The useService method remains unaltered. In callService, the name of the callback function is specified initially, followed by the object 'a', thereby, furnishing all the values in a single stroke. Finally, the parameters to the function in the object are supplied. You may have noticed that there are too many overheads for a single function named callService.

 

The function bbb eventually gets called, and it overrides the onresult value, which is specified in the input element. Thus, we witness two message boxes. The first displays hi0, while the second displays bbb30. On modifying the value of the async property to false                (i.e. a.async = false), the client is prevented from proceeding further, until the SOAP packet returns. Therefore, the functions aaa and bbb shall never get called. It is advisable to use this type of synchronous behaviour sparingly and with deliberate care.

 

Asynchronous Execution

 

a.asmx

<%@ WebService Language="C#" class="zzz" %>

using System;

using System.Web.Services;

public class zzz {

[WebMethod]

public int abc(int i, int j)

{

return i + j;

}

}

 

The aa.wsdl file remains the same and hence is not displayed.

 

 

a.cs

using System;

public class aaa

{

public static void Main()

{

zzz a= new zzz();

AsyncCallback c = new AsyncCallback(abc);

IAsyncResult r = a.Beginabc(10,20,c,a);

while (r.IsCompleted == false)

{

Console.WriteLine(DateTime.Now);

}

Console.ReadLine();

}

public static void abc(IAsyncResult a)

{

zzz d = (zzz) a.AsyncState;

int r;

r = d.Endabc(a);

Console.Write(r);

}

}

 

zzz.cs

public System.IAsyncResult Beginabc(int i, int j, System.AsyncCallback callback, object asyncState)

{

return this.BeginInvoke("abc", new object[] {i,j}, callback, asyncState);

}

public int Endabc(System.IAsyncResult asyncResult)

{

object[] results = this.EndInvoke(asyncResult);

return ((int)(results[0]));

}

 

Output

DatTime….

30

 

 

z.bat

del *.exe

del *.dll

del zzz.cs

wsdl aa.wsdl

csc /t:library zzz.cs

csc a.cs /r:zzz.dll

a

 

SOAP request

<abc xmlns="http://tempuri.org/">

<i>10</i>

<j>20</j>

</abc>

 

SOAP response

<abcResponse xmlns="http://tempuri.org/">

<abcResult>30</abcResult>

</abcResponse>

 

We commence with the smallest asmx file, which has a single function named abc. The quandary that we may face at this juncture is that, if the function abc on the server-side uses up an hour to complete execution, the program would have to wait at the call, until the function finished execution, and thereby, bringing the execution of the remaining code to a grinding halt. So, would it not be a sagacious move to let the code execution continue, even after the function call is completed? Once the call has been completed, it could notify another function and pass it the return value. This program goes behind the scenes to reveal the mechanics of implementing an asynchronous call!

 

Since the asmx file resides on the server, it displays the familiar abc function, devoid of any alteration. However, in the C# client, numerous modifications have been carried out.

 

The object 'a' is an instance of the class zzz, and the object 'c' is an instance of class AsyncCallback. The name of a static function abc in class aaa, is passed to the constructor of the AsyncCallback delegate. Thereafter, in place of the function abc, the function Beginabc gets called with four parameters:

     The first two parameters are for the abc function.

     The third parameter is c, which is the AsyncCallback object. This delegate calls the function abc, when the function abc on the remote server completes execution.

     The fourth parameter is the zzz object itself.

           

It is impossible to estimate the time frame in which the abc function is likely to accomplish its task. Therefore, the remaining code goes on with its execution. The IsCompleted property of type boolean contains the value of false, till the function on the server completes execution, or till the SOAP response packet has been received. Thus, we quit out of the loop when the IsCompleted member returns true. While the loop is in progress, the only code that is executed is the WriteLine function, which contains the DateTime value. Once the IsCompleted value changes to true, the abc function gets called.

 

The function abc is passed a parameter 'a', of type IAsyncResult, which contains a property called AsyncState. This property represents the zzz object. Using this zzz object, the function Endabc is called, which eventually returns the answer from the remoted function. This value is then displayed on the Console. Thus, the proxy generates two functions, viz. Beginabc and Endabc.  Instead of Invoke, a function named BeginInvoke is employed, which is passed the name of the function in a string form, followed by an array of objects for the parameters. This is followed by the name of the callback delegate, and finally, by the zzz object. The Endabc function uses the EndInvoke function to return an array of objects, from which, the first int is returned.

 

It is highly improbable that you are able to discern the method of invocation that has been employed, by merely examining the SOAP packets. Therefore, in the SOAP world, mundane issues such as, synchronous and asynchronous calls, pale into insignificance. Thus, SOAP has to lean on various other infrastructural crutches, in order to work effectively. In the real world, it cannot be used by itself, as a standard.  However, issues regarding distributed computing are given due consideration by the SOAP standard.

 

 

a.cs

using System;

public class aaa

{

public static void Main()

{

zzz a= new zzz();

IAsyncResult r = a.Beginabc(10,20,null, null);

Console.WriteLine("Before");

r.AsyncWaitHandle.WaitOne();

int c;

c = a.Endabc(r);

Console.WriteLine(c);

}

}

 

Output

Before

30

 

There are myriad ways of implementing asynchronous behaviour. Since there is neither a callback function abc, nor any delegate, the last two parameters of the Beginabc function are assigned the value of null. When the Beginabc function is called, the WaitOne function is executed, which waits until the function abc completes execution.

 

The program does not consume any resources; instead, it sleeps until a SOAP response is received. The familiar Endabc function is employed to obtain the answer. The mileage that you wish to derive, shall determine the most optimal mechanism of implementing asynchronous behaviour.