Bob Swart (aka Dr.Bob)
Delphi 6 Web Services (1) toepassen

Dit artikel is het eerste deel van een korte serie over Delphi 6 en Web Services. In dit eerste deel laat ik zien hoe we bestaande Web Services kunnen gebruiken in Delphi 6 toepassingen, en in het tweede deel zal ik laten zien hoe we zelf Web Services kunnen implementeren in Delphi 6.
Enkele Delphi 6 Web Services die ik heb geschreven zijn reeds beschikbaar voor daadwerkelijk gebruik, zie ook Dr.Bob's SOAP Bubbles.

Web Services
Een Web Service is een algemene term, en wordt tegenwoordig te pas en te onpas gebruikt. Eigenlijk kan een Web Service nog het best omschreven worden als een "next generation" gedistribueerde toepassing. Ter vergelijking: in vorige versies van Delphi (of C++Builder) konden we multi-tier toepassingen bouwen waarbij we als communicatieprotocol konden kiezen uit DCOM, TCP/IP sockets, HTTP or zelfs CORBA. Naast het communicatieprotocol, had de keuze vaak ook betrekking op de representatie van het server object aan de client kant. Als we bijvoorbeeld CORBA gebruiken krijgen we al een heleboel extra's, en zijn we zelfs platform en taal onafhankelijk bezig. DCOM is wel taalonafhankelijk maar draait alleen onder Windows, terwijl TCP/IP sockets en HTTP wel platform- en taalonafhankelijk zijn, maar weinig vastleggen over de vorm van het object zelf, waardoor het in praktijk moeilijk is om een eenduidige standaard te vinden als je daadwerkelijk met een andere omgeving wilt werken (wat dat betreft is MIDAS - of DataSnap - nog niet echt een standaard om buiten de Borland ontwikkelomgevingen toe te passen).

SOAP
SOAP (Simple Object Access Protocol) is ook een hype woord (net als Web Services), en is in feite een nieuwe manier om de tiers met elkaar te verbinden. Het bestaat eigenlijk al een paar jaar, maar is pas de laatste tijd (erg) veel onder de aandacht gekomen, met name in combinatie met Web Services en XML.
SOAP gebruikt XML als taal om het (server) object te beschrijven, of eigenlijk het interface ervan. Terugkomend op Web Services: een Web Service kan gezien worden als een remote object (draaiend op een web server), waarbij de methoden (het interface) aan de buitenwereld beschikbaar worden gemaakt door middel van SOAP. De beschrijving van het interface van de Web Service worden gedaan met WSDL (Web Service Description Language), wat weer een subset van XML is.
Voor Delphi 6 gebruikers is het vast fijn om te weten dat de WSDL voor onze Web Services automatisch zal worden gegenereerd, zodat we ons daar in ieder geval geen zorgen over hoeven te maken. Deze keer echter wil ik met name stilstaan bij het gebruik van bestaande Web Services (in Delphi 6).

Web Services gebruiken
Voordat we een bestaande Web Service kunnen gebruiken zullen we hem eerst moeten vinden. Er zijn verschillende plaatsen, zoals http://www.xmethods.org en http://www.salcentral.com waar je lijsten met Web Services kunt vinden (plus de omgeving waarin ze gemaakt zijn, zoals Lucin SAL, MS .NET en Delphi uiteraard). Deze keer wil ik gebruik maken van twee bestaande Web Services, en ze achterelkaar "uitvoeren", namelijk de "Number to Words" (van Tom Chamberlain, geschreven in Delphi) en de beroemde BabelFish service (van AltaVista, geïmplementeerd door xmethods zelf met SOAPLite). Als resultaat wil een een getal omzetten in engelse woorden, en dat dan vertalen naar het Frans, Duits of liever nog het Nederlands.

Number to Words
De "Number to Words" web service is geschreven in Delphi 6, en de WSDL beschrijving kan gevonden worden als http://powerofzen.com/cgi-bin/wordsforchecks.exe/wsdl/IWordsForCheck (deze URL produceert de WSDL: een XML listing die we nodig hebben om een import unit voor Delphi 6 te genereren). Start nu een nieuw project in Delphi 6 om de web service te gaan gebruiken. Bewaar dit project als Client.dpr. We moeten nu eerst de import unit voor de IWordsForCheck interface laten genereren. Hiervoor moeten we via File | New | Other naar de WebServices tab van de Object Repository, en dan de Web Services Importer kiezen. In de Web Services Importer dialoog moeten we vervolgens weer de URL voor de WSDL van "Number to Words" gebruiken:

Klik nu op de Generate knop om de import unit voor het IWordsForCheck interface te genereren. De gegenereerde code voor het IWordsForCheck interface in de import unit zou er als volgt uit moeten zien:

  type
    IWordsForCheck = interface(IInvokable)
      ['{C3530212-5440-4CC4-82ED-5AA3F0984AAF}']
      function GetWordsForCheck(const Value: Double): WideString; stdcall;
    end;
De IWordsForCheck interface is afgeleid van de IInvokable interface (hierdoor kunnen we de remote web service ook echt gebruiken).

Calling GetWordsForCheck
Keer terug naar de main unit van het Delphi project Client.dpr, en zorg dat de import unit aan de uses clause wordt toegevoegd (zodat het interface IWordsForCheck bekend is). Zet nu drie editboxen op het main form. De eerste editbox (ebInput) zal het bedrag in cijfers bevatten. De tweede editbox (ebOutput) zal het bedrag in woorden bevatten - in het Engels dus. De derde editbox (ebBabel) zal het bedrag wederom in woorden bevatten, maar deze keer vertaald door BabelFish naar bijvoorbeeld Frans, Duits of zelfs Spaans. We hebben nog een button nodig om het converteren in gang te zetten, maar voordat we dit alles kunnen afmaken hebben we eerst nog iets anders nodig van de WebServices tab: een THTTPRIO component (dat staat voor Remote Invokable Object over HTTP); de eerste van links.

HTTPRIO
Weet je de URL nog voor de WSDL van IWordsForCheck? Welnu, deze URL hebben we straks weer nodig, omdat de import unit namelijk alleen maar de definitie van het IWordsForCheck interface bevat, en niet de vindplaats van de web service zelf (die kan je rustig op een andere locatie neerzetten, zolang je maar aan de HTTPRIO component altijd precies laat weten waar hij te vinden is). De HTTPRIO component heeft hiervoor een property WSDLLocation die dus de waarde http://powerofzen.com/cgi-bin/wordsforchecks.exe/wsdl/IWordsForCheck moet krijgen. Open hierna de drop-down combobox voor de Service property en kies IWordsForCheckservice (het is de enige keuze). Tot slot moeten we ook de drop-down combobox voor de Port property open en IWordsForCheckPort kiezen (wederom de enige keuze, dus da's makkelijk).
De HTTPRIO component is nu klaar om gebruik te maken van de (remote) web service. Daadwerkelijk gebruik vindt plaats in de OnClick event handler van de "Number to Words" button. Als eerste moet we het IWordsForCheck interface uit de HTTPRIO halen zodat we het interface (en de remote implementatie door de web service) kunnen aanroepen. Als we eenmaal het interface hebben, kunnen we de enige methode GetWordsForCheck eindelijk aanroepen:

  procedure TForm1.Button1Click(Sender: TObject);
  var
    WordsForCheck: IWordsForCheck;
    Number: Integer;
  begin
    WordsForCheck := (HTTPRIO1 AS IWordsForCheck); // Connect
    Number := StrToInt(Edit1.Text);
    Edit2.Text := WordsForCheck.GetWordsForCheck(Number);
  end;
Als we bijvoorbeeld 42 in de eerste editbox zetten en op de "Number to Words" knop drukken zal een verbinding met de remote web service gemaakt worden, het (geïmplementeerde) interface IWordsForCheck zal uit de HTTPRIO gehaald worden, en de methode GetWordsForCheck zal het getal 42 omzetten in de woorden "FORTY TWO DOLLARS AND 00 CENTS".

BabelFish
We zijn echter nog niet helemaal klaar, want ik wou de woorden ook nog kunnen vertalen naar het Frans, Spaans of Duits met behulp van de BabelFish (helaas ondersteunt die geen Nederlands). De BabelFish vertaal web service is gebaseerd op AltaVista's BabelFish - voor meer informatie zie http://www.xmethods.com/detail.html?id=14, waar je onder andere een lijst met mogelijke vertalingen kan vinden.
Het moet nu niet moeilijk meer zijn om de WSDL URL http://www.xmethods.net/sd/BabelFishService.wsdl te gebruiken om een tweede import unit te genereren (voor de BabelFish web service) en deze import unit ook aan de uses clause van onze main form toe te voegen. Gebruik een tweede HTTPRIO component en zorg dat de WSDLLocation property daarvan naar dezelfde WSDL URL wijst. Vergeet niet om de Service en Port properties van een waarde te voorzien (de enige keuze uit de comboboxen), en vul vervolgens de code van de OnClick event handler als volgt aan (de optie en_de zorgt voor een vertaling van Engels naar Duits):

  procedure TForm1.Button1Click(Sender: TObject);
  var
    WordsForCheck: IWordsForCheck;
    Number: Integer;
    BabelFish: BabelFishPortType;
  begin
    WordsForCheck := (HTTPRIO1 AS IWordsForCheck); // Connect
    Number := StrToIntDef(Edit1.Text,0);
    Edit2.Text := WordsForCheck.GetWordsForCheck(Number);
    BabelFish := (HTTPRIO2 AS BabelFishPortType); // Connect
    Edit3.Text := BabelFish.BabelFish('en_de',Edit2.Text)
  end;

Helaas is de BabelFish vertaler wel goed maar niet zo slim, omdat ieder woord apart wordt vertaald. Voor "forty two" krijgen we "vierzig zwei" wat natuurlijk niet de bedoeling is. Maar ja, het gaat om het idee, nietwaar?
Gezien het feit echter dat de BabelFish geen vertaling van of naar het Nederlands ondersteunt zal ik de volgende keer mijn eigen "NumberToWords" bouwen. Als een Delphi 6 Web Service wel te verstaan. Tot dan!

Dit artikel is een vrije vertaling van mijn artikel over Delphi 6 Web Services geschreven voor de TechRepublic website. Mocht iemand nog vragen, opmerkingen of suggesties hebben, dan hoor ik die het liefst via . Wie meer wil weten over XML, SOAP en het gebruik (en de bouw) van Web Services moet zeker eens overwegen om zich in te schrijven voor een van mijn Delphi Clinics.


This webpage © 1999-2006 by webmaster drs. Robert E. Swart (aka - www.drbob42.com). All Rights Reserved.