Dienstag, Juni 28, 2005

Proxies for WebServices in JavaScript

If you want to implement a communication from Javascript to WebServices using SOAP it is very important to use an approach with a small amount of code. Complex and long scripts tend to be buggy.

From the languages and programming environments like C, the .NET CLR and Java we are know proxy generation mechanisms based on IDL and RPC for a long time. These generated classes and files enable the programmer to call a server-side method by calling a local method with the same name. The implementation of the network transfer is taken off your application code.

For WebServices there is also a description standard called WSDL http://www.w3.org/TR/wsdl that fully describes a Webservice communication and a WSDL Compiler can generate those proxy classes in Sourcecode or binary format using this information only.

JavaScript objects on the client

Creating proxy objects is also possible using JavaScript so that a local call of a method results in a call of the corresponding method in the WebService on the server using the same parameters and brining the result back to the client.

To create such Proxy Objects we only need one line of code as we will see below.

The implementation of the real communication is implemented in the ajax include file in the webservice region. In this script include the variable proxies is created as an empty Objects. All local service objects and all local methods will be attached to this object. Calling a server-side Methods looks like this:

proxies.CalcService.func = displayFactors; // async result
proxies.CalcService.CalcPrimeFactors(12); // call

Also a synchronous version can be used. The func attribute must be null and the result of the server-side method is directly returned from the client method.

var factors = proxies.CalcService.CalcPrimeFactors(12);

Using this approach proxies ist the only one global variable that we need. Conflicts with other variables are minimized.

All the information that is needed to make the SOAP call is attached to every method object and another object is used to hold the information about the webservice.

Verwendung der Eigenschaften der WebService Objekte
EigenschaftUsage
proxies.service.urlURL of the WebService
proxies.service.nsNamespace of the WebServices
proxies.service.function()Calling a server-side method
proxies.service.function.fnameName of the method
proxies.service.function.actionsoapaction of the method
proxies.service.function.paramsArray with the names of the parameters
proxies.service.function.funcFunction receiving the result
proxies.service.function.onExceptionFunction to handle an exception
proxies.service.function.corefuncDebugging helper function
proxies.service.function.serviceLink back to the service object

In JavaScript this code looks like this:

[in ajax.js:]
var proxies = new Object();

[per WebService]
// JavaScript proxy for webservices
// A WebService for the calculation of prime factors.
proxies.CalcService = {
  url: "http://localhost:1049/CalcFactors/CalcService.asmx",
  ns: "http://www.mathertel.de/CalcFactorsService/"
} // proxies.CalcService

[per WebServiceMethode]
// Add 2 numbers.
proxies.CalcService.AddInteger = function () { return(callSoap(arguments)); }
proxies.CalcService.AddInteger.fname = "AddInteger";
proxies.CalcService.AddInteger.service = proxies.CalcService;
proxies.CalcService.AddInteger.action = "http://www.mathertel.de/CalcFactorsService/AddInteger";
proxies.CalcService.AddInteger.params = new Array("number1", "number2");

If you only have to realize a small application you can easily create this code manually by reading all the information you need from the webservice description. Retrieving such a description is very easy when implementing in ASP.NET. You navigate to the URL of the webservice and use the Link that is available on this page. You can also attach a WSDL Parameter:

See: http://localhost/CalcFactors/CalcService.asmx?WSDL

A Proxy generator for JavaScript

The simplest form for a WSDL to Javascript Compiler to generate tese proxy objects uses a single XSLT transformation that generates Javascript.

The Page GetJavaScriptProxy.aspx implements this by retrieving the WSDL from the WebService and using wsdl.xslt for the transformation.

To get a proxy for a WebService yopu only need to ust one <script> Element with the URL to the GetJavaScriptProxy Page:

<script type="text/javascript" src="GetJavaScriptProxy.aspx?CalcService.asmx"></script>

You do not have to write the script fort he proxy yourself as you can see and you only need one html tag.

The files for the implementation are available on the sample webside (see sidebar).

Freitag, Juni 17, 2005

Using WebServices with AJAX Applications

There are still some disadvantages with many available AJAX frameworks on the web and also with my preceding implementation:

  • For each necessary functionality a special page must be realized
  • The url may exceed a length of more than a few 100 chars and will bring up problems.
  • The implementation on the server consists of code fragments used for the communication of parameters and the return value together with the application specific code.

Here it is obvious that using the server side communication infrastructure of webservices brings in some huge advantages:

  • The same functionality can also be used from other webservice enabled applications like Excel.
  • Multiple methods can be implemented together in one class so it is possible to choose the right granularity for bigger collections of webservices.
  • You can use datatypes
  • There is exception handling (more on this later)
  • A proxy can be created for the client that enables an easy implementation of calling a server side method. (more on this soon)
  • The existing SOAP and WSDL standards in the current available version (Spring 2005) are perfect usable on http and https connections. The circumstances for transferring html over http are identical and usable without any problems for webservices. The actual discussions about extending the WebService Infrastructure with security features and routing soap messages are not needed and SOAP is as secure as the web is in this scenario.

WebServices can be implemented very easily in ASP.NET so I prefer this platform in my samples.

The implementation of a WebService for the calculation of the prime factors can be found in CalcService.asmx in ths sample website. The core implementation is the same as in Request.aspx.

<%@ WebService Language="C#" Class="Service" %>

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;

[WebService(Namespace = "http://www.mathertel.de/CalcFactorsService",
  Description="A WebService for the calculation of prime factors.")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService {

  ...
  

  [WebMethod(Description="Calculate all prime factors of a given number.")]
  public string CalcPrimeFactors(string inputText) {
    string outputText = String.Empty;
    UInt64 prime;  // try this factor (only primes will match!)
    UInt64 number; // product of the remaining factors

    if ((inputText == null) || (inputText.Length == 0) || (inputText == "0"))
      return (null);

    prime = 2; // start with 2
    number = UInt64.Parse(inputText);

    while ((number > 1) && (prime * prime <= number)) {
      if (number % prime != 0) {
        // try the next factor (slowly)
        prime += (prime == 2UL ? 1UL : 2UL); 

      } else {
        // found a factor !
        outputText = outputText + " " + prime;
        number = number / prime;
      } // if
    } // while

    if (number > 1) {
      // the last factor (a prime) is here.
      outputText = outputText + " " + number;
    }

    return (outputText);

  } // CalcPrimeFactors

  ...

} // class

see CalcService.asmx on the sample web side.

The special thing here, compared to the previous sample using Request.aspx with a http GET command, is that the functional characteristics of the server side operation gets clear. There is no need for the programmer to care about the details of the communication Because there no usable SOAP client available in the current browsers there is more overhead in the JavaScript programming in the browser for implementing the SOAP protocol as far as we need it. There is in deed a SOAP interface available in Firefox but this implementation is not working correctly and is only partial implemented. Fortunately the assembling of the SOAP request and analyzing the result is also possible with the well known XMLHTTP Object.

// call the server using the SOAP encoding
xmlObj = new ActiveXObject("Microsoft.XMLHTTP");
xmlObj.Open("POST", "http://localhost/CalcFactors/Service.asmx", true);
xmlObj.setRequestHeader("SOAPAction", "http://www.mathertel.de/CalcFactorsService/CalcPrimeFactors");
xmlObj.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlObj.onreadystatechange = RetrievePrimeFactors;
var soapText = "<?xml version='1.0' encoding='utf-8'?>"
  + "<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>"
  + "<soap:Body>"
    + "<CalcPrimeFactors xmlns='http://www.mathertel.de/CalcFactorsService'>"
      + "<inputText>" + inputText + "</inputText>"
    + "</CalcPrimeFactors>"
  + "</soap:Body>"
+ "</soap:Envelope>";
xmlObj.Send(soapText);

...

// the response is inside the <CalcPrimeFactorsResult> tag
outputText = xmlObj.ResponseText;
p = outputText.indexOf("<CalcPrimeFactorsResult>");
if (p > 0) {
  outputText = outputText.substr(p+24);
  outputText = outputText.substr(0, outputText.indexOf("<"));
} // if

This implementation is only used to show how the SOAP protocol works but has no error handling and lacks of being robust.

This implementation can be found in the page CalcFactorsServerSoap.htm on the sample website. It only works for IE.

The server side code get dramatically simplified when using WebServices. For the client there also exists a good solution.

Stay tuned.

The files for the implementation are available on the sample WebSite

Sonntag, Juni 12, 2005

Native AJAX Programming

With the Ajax model the execution of a web page is processed in 2 phases:

Phase 1: Loading the page

During this synchronously implemented phase the client loads the "static" part of the application. That corresponds to displaying a form or a list without any concrete data.

The code for the page is assembled and delivered to the browser. It makes no big difference if plain HTML, generic Javascript or Javascript includes are used.

The http answer of this first call can be delivered in many with a hint for the client that the local browser cache can be used and therefore the server will not be asked again for this code. The displaying of a page in this situation is very fast and efficiently because the bytes are retrieved from the local cache and no network delays occur.

See http://msdn.microsoft.com/library/en-us/dnwebgen/html/ie_introfiddler2.asp

Phase 2: Loading data from the server

This phase is used for retrieving more information from the web server and then combining it into the already delivered html. This can be repeated several times while the initial page is still loaded.

That can be the current list of the emails, (Outlook Web ACCESS, GMail) or the data changed since the last call (GMail) or additional information to a search word (Google Suggest).

There are also non HTML/javascript solutions possible. Google Maps uses variable URLs with parameters on image objects to retrieve the bitmaps that are part of the current shown map.

The AJAX model must be considered in both phases. In the first phase the necessary (Javascript) code must be delivered. In the second phase this code must be used to get the information from the server.

The core algorithm of the example, the computation of the prime factors of a number, can also be implemented quite simply on the server. A url with the number in a parameter is requested from the server and the http answer will return the list of factors. The Javascript method from CalcFactorsAsync1.htm can be converted quite easily in C # and over URL is then called:

http://www.mathertel.de/AjaxEngine/S01_AsyncSamples/CalcFactorsRequest.aspx?number=266712

The source code of this sample is available on the sample WebSite.

That is the simple version of the function for the computation of the prime factors. The clearly more complex variant of the code from CalcFactorsAsync2.htm is not needed. Thus programming is simplified for the server-side execution again.

To start such a request from the client a quite simple code is sufficient:

var xmlObj = new ActiveXObject("Microsoft.XMLHTTP");
xmlObj.Open("GET", "Request.aspx?number=" + inputText, false);
xmlObj.send();
outputText = xmlObj.responseText;

A complete implementation sample (CalcFactorsServer1.htm) is available on the sample WebSite.

So we can call the server. The answer of such an inquiry can, as we know, take up some long (cpu) time and the send() method waits for the answer of the server. During this time and with the above implementation the client does freeze and user input events do not execute. Again we have a locking synchronous situation.

Sending the parameters and receiving of the answer therefore must be implemented in 2 different methods so that in the meantime the events of the keyboard and the mouse in the browser can execute.

The XMLHTTP object must be defined global for it is still available at the time of the transmission of the result. A new method RetrievePrimeFactors is called when the result is present and the field for the result is updated.

A complete implementation sample (CalcFactorsServer2.htm) is available on the sample WebSite

With this implementation we reach the kind of the Browser application, that one is called an AJAX application. No real XML is used until know but in the end final same result is achieved.

The files for the implementation are available on the sample WebSite (see sidebar)