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.