Bob Swart (aka Dr.Bob)
Web Services gebruiken met Delphi 6.02 Professional

Native Delphi ondersteuning voor Web Services was tot voor kort alleen te vinden in Delphi 6 Enterprise. Maar met Delphi 6 Update 2 kunnen nu ook ontwikkelaars met Delphi 6.02 Professional gebruik maken van Web Services (lees: voor het maken van Web Service clients - voor de bouw van de Web Service "engines" is nog steeds de Enterprise editie van Delphi 6, C++Builder 6 of Kylix 2 noodzakelijk).
In dit artikel zal ik laten zien hoe eenvoudig het is om met Delphi 6.02 Professional gebruik te maken van de vele Web Services die van de dag reeds beschikbaar zijn (en een belangrijk onderdeel van .NET vormen).

Web Services
Wat was ook al weer een Web Service? Je kan het zien als een (remote) engine, die in staat is om taken (de methoden) uit te voeren. Het voordeel is gestructureerd hergebruik van bestaande bouwstenen (die bovendien cross-language en cross-platform kunnen zijn).
De engine wordt benaderd via SOAP (het Simple Object Access Protocol), en de beschrijving van wat de Web Service kan doen wordt gedaan met behulp van de WSDL (Web Service Description Language). Gelukkig hoeven we daar weinig tot niks van te weten, aangezien Delphi dat allemaal voor ons omzet in leesbare Object Pascal code.

Web Service Engines
Enkele Delphi 6 Web Services (de engines) die ik heb geschreven in Delphi 6 en Kylix 2 zijn reeds beschikbaar voor daadwerkelijk gebruik (zie ook Dr.Bob's SOAP Bubbles), zoals de IHitchHiker, ITicTacToe, IRoman, IDutch, IHeadline en IEuro (zowel in Kylix 2 als Delphi 6).
Met name de IEuro is een handige Web Service die ons instaat stelt om bedragen in de ene munteenheid om te zetten in euros (of terug). Ik heb deze Web Service zowel in Delphi 6 als in Kylix 2 gebouwd, dus kunnen we kiezen voor gebruik van de Web Service engine onder Windows (als http://www.eBob42.com/cgi-bin/Euro42.exe/wsdl), of onder Linux (als http://www.drbob42.co.uk/cgi-bin/Euro42/wsdl). Uiteraard werken ze allebei hetzelfde.

Delphi 6.02 Professional
Na toepassing van Update 2 op Delphi 6 Professional, zien we plotseling een extra WebServices tab in het Component Palette (meer hierover straks), en een extra WebServices tab in de Object Repository. Deze gaan we gebruiken voor onze Web Service Euro Calculator client toepassing.
Doe File | New Application, en bewaar het gegenereerde main form in MainForm.pas, en het project zelf in EuroCalc.dpr. Doe vervolgens File | New - Other en ga naar de WebServices tab van de Object Repository. Hier zien we de nieuwe WSDL Importer, die in staat is om van een WSDL definitie (van een Web Service) een Object Pascal import unit te genereren voor ons.

Tot voor kort was de WebServices tab voorbehouden aan Enterprise gebruikers van Delphi 6 of Kylix 2. De recente lancering van C++Builder 6 bracht hier echter verandering in, doordat C++Builder 6 Professional ook al in staat is om Web Services te importeren. Delphi 6 Update 2 is dus niet alleen gebruikt om een aantal 'defecten' op te lossen en Delphi 6 compatible te maken met C++Builder, maar ook om Delphi 6 in de pas te laten lopen met C++Builder 6 (wat betreft de ondersteuning voor Web Services in de Professional versie).
De WSDL definitie van de IEuro Web Service te vinden op http://www.eBob42.com/cgi-bin/Euro42.exe/wsdl en http://www.drbob42.co.uk/cgi-bin/Euro42/wsdl. Een van deze URLs moeten we opgeven in de WSDL Import Wizard, alhoewel we ook een .xml bestand zelf kunnen opgeven (waar de WSDL voor de IEuro interface in opgeslagen is).

Door op Next te klikken zien we meteen de gegenereerde code en per knoop in de treeview een aantal attributen. Zo bestaat mijn IEuroservice uit één interface genaamd IEuro, dat twee methods bevat: FromEuro en ToEuro.
Beide methoden hebben ze een eerste argument "Currency" die als waarde één van de 12 euro munteenheden kan hebben (dus FIM, BEF, FRF, ITL, ATS, IEP, NLG, LUF, PTE, ESP, DEM, en GRO). Het tweede argument bevat steeds het bedrag dat ofwel omgerekend moet worden naar euros, of van euros terug naar de meegegeven munteenheid.

Voordat je op Finish klikt om de code voor de import unit daadwerkelijk te genereren, kun je op de Options button klikken om wat Code Generation opties te zetten (of Connection opties).

Ik wijzig hier meestal niks in, dus klik hier op Cancel (om terug te komen in de WSDL Import Wizard), en klik daarna op de Finish button in de WSDL Import Wizard om de import unit voor IEuro te genereren. Dit levert de volgende code op, in de unit IEuro1.pas:
  // ************************************************************************ //
  // The types declared in this file were generated from data read from the
  // WSDL File described below:
  // WSDL     : http://www.eBob42.com/cgi-bin/Euro42.exe/wsdl/IEuro
  // Version  : 1.0
  // (2002-02-24 14:25:54 - $Revision:   1.9.1.0.1.0.1.9  $)
  // ************************************************************************ //

  unit IEuro1;
  interface
  uses
    InvokeRegistry, Types, XSBuiltIns;

  type
    // ************************************************************************ //
    // The following types, referred to in the WSDL document are not being represented
    // in this file. They are either aliases[@] of other types represented or were referred
    // to but never[!] declared in the document. The types from the latter category
    // typically map to predefined/known XML or Borland types; however, they could also
    // indicate incorrect WSDL documents that failed to declare or import a schema type.
    // ************************************************************************ //
    // !:string          - "http://www.w3.org/2001/XMLSchema"
    // !:double          - "http://www.w3.org/2001/XMLSchema"


    // ************************************************************************ //
    // Namespace : urn:Euro-IEuro
    // soapAction: urn:Euro-IEuro#%operationName%
    // transport : http://schemas.xmlsoap.org/soap/http
    // style     : rpc
    // binding   : IEurobinding
    // service   : IEuroservice
    // port      : IEuroPort
    // URL       : http://www.eBob42.com/cgi-bin/Euro42.exe/soap/IEuro
    // ************************************************************************ //
    IEuro = interface(IInvokable)
    ['{3D819D7A-85D1-4490-75D7-61CC7232A91E}']
      function  FromEuro(const Currency: String; const Amount: Double): Double; stdcall;
      function  ToEuro(const Currency: String; const Amount: Double): Double; stdcall;
    end;

  function GetIEuro(UseWSDL: Boolean=System.False; Addr: string=''): IEuro;


  implementation
  uses
    SOAPHTTPClient;

  function GetIEuro(UseWSDL: Boolean; Addr: string): IEuro;
  const
    defWSDL = 'http://www.eBob42.com/cgi-bin/Euro42.exe/wsdl/IEuro';
    defURL  = 'http://www.eBob42.com/cgi-bin/Euro42.exe/soap/IEuro';
    defSvc  = 'IEuroservice';
    defPrt  = 'IEuroPort';
  var
    RIO: THTTPRIO;
  begin
    Result := nil;
    if (Addr = '') then
    begin
      if UseWSDL then
        Addr := defWSDL
      else
        Addr := defURL;
    end;
    RIO := THTTPRIO.Create(nil);
    try
       if UseWSDL then
      begin
        RIO.WSDLLocation := Addr;
        RIO.Service := defSvc;
        RIO.Port := defPrt;
      end
      else
        RIO.URL := Addr;
      Result := (RIO as IEuro);
    finally
      if Result = nil then
        RIO.Free;
    end
  end;


  initialization
    InvRegistry.RegisterInterface(TypeInfo(IEuro), 'urn:Euro-IEuro', '');
    InvRegistry.RegisterDefaultSOAPAction(TypeInfo(IEuro), 'urn:Euro-IEuro#%operationName%');
  end.
Deze code is geheel nieuw (ten opzichte van de code die eerder werd gegenereerd), en biedt ook meer ondersteuning dan er vóór Update 2 van Delphi 6 beschikbaar kwam. We kunnen nu namelijk de function GetIEuro aanroepen om het interface op te halen en meteen te gebruiken. We hoeven dus niet langer zelf een HTTPRIO component te gebruiken (van de WebServices tab van het Component Palette), alhoewel deze mogelijkheid natuurlijk nog wel beschikbaar is voor wie de HTTPRIO component van de WebServices tab zelf wil gebruiken (de andere twee zijn niet eens nodig voor dit voorbeeld):

Om de verschillen tussen beide benaderingen te laten zien zal ik nu de FromEuro op de oude manier implementeren (met een expliciete HTTPRIO component), en de ToEuro op de nieuwe manier (door de GetIEuro aan te roepen).
Voordat we zover zijn moeten we eerst de MainForm aanpassen voor gebruik van de Web Service. We hebben een RadioGroup nodig, met daarin de twaalf 3-letterige monetaire eenheden, twee edit boxen (EditInput en EditOutput) en twee buttons (btnFromEuro en btnToEuro).
En natuurlijk de HTTPRIO component van de WebServices tab:

De HTTPRIO component moeten we handmatig instellen om gebruik te kunnen maken van de IEuro Web Service. Dit kan op twee manieren. De eerste manier werkt voor Delphi 6 en Kylix 2 Web Services, en houdt in dat we alleen de URL property moeten laten wijzen naar http://www.eBob42.com/cgi-bin/Euro42.exe/soap/IEuro. De tweede manier werkt voor alle omgevingen (inclusief Delphi 6 en Kylix 2), en houdt in dat we eerst de WSDL property moeten laten wijzen naar http://www.eBob42.com/cgi-bin/Euro42.exe/wsdl/IEuro (met dus /wsdl in plaats van /soap), en vervolgens moeten we de Service property de waarde IEuroservice geven, en de Port property de waarde IEuroPort. Hierna kunnen we de FromEuro methode aanroepen in de OnClick event handler van de FromEuro button:
  procedure TForm1.BtnFromEuroClick(Sender: TObject);
  begin
    EditOutput.Text :=
      FloatToStr((HTTPRIO1 AS IEuro).FromEuro(
        RadioGroupCurrency.Items[RadioGroupCurrency.ItemIndex],
        StrToFloat(EditInput.Text))) +
      #32 + RadioGroupCurrency.Items[RadioGroupCurrency.ItemIndex];
  end;
Het alternatief (voor het gebruik van de HTTPRIO component), en nieuw in Update 2 van Delphi 6, is het gebruik van de gegenereerde function GetIEuro. Deze heeft twee default argumenten (die bepalen of we de URL of de WSDL gebruiken), en geeft direct het IEuro interface terug. Het aanroepen van de ToEuro methode in de OnClick event handler van de ToEuro button gaat daarmee als volgt:
  procedure TForm1.BtnToEuroClick(Sender: TObject);
  begin
    EditOutput.Text :=
      FloatToStr(GetIEuro.ToEuro(
        RadioGroupCurrency.Items[RadioGroupCurrency.ItemIndex],
        StrToFloat(EditInput.Text))) + ' EUR'
  end;
In beide gevallen gaat het gebruik van het IEuro interface hetzelfde. maar de nieuwe function GetIEuro maakt het gebruik van de Web Service nog eenvoudiger dan hiervoor, omdat we nu niet langer een expliciete HTTPRIO component nodig hebben!
Het resultaat is een handige Euro Calculator:

Meer Informatie
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 mijn Delphi Clinic over BizSnap.


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