Web Services gebruiken met Delphi 6.02 Professional |
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).
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.
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).
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!
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.