Delphi Clinic | C++Builder Gate | Training & Consultancy | Delphi Notes Weblog | Dr.Bob's Webshop |
|
Using Kylix 2 Web Services in Delphi 6
Two months ago, we used Kylix 2 Enterprise to build a special Euro-conversion Web Service with two methods: FromEuro and ToEuro.
This time, we'll "consume" this web service by writing a client in Delphi 6 Enterprise as well as Kylix 2 Enterprise (with little changes).
Note that this article was written prior to Delphi 6 Update 2 (the version that makes importing/consuming Web Services even easier).
Internet Deployment
Before we start, I have a little surprise for you: the web service we've made last time is now deployed and actually available on the internet.The URL is http://www.drbob42.co.uk/cgi-bin/Euro42 and needs /wsdl in order to get the definition using the Web Service Description Language.I've deployed the web service on a Linux machine running Apache, but without Kylix installed, so this shows that you can easily deploy your web services out there on the internet (you obviously need to place it a cgi-bin directory and give it execute rights, but you don't need to deploy any additional files).
Web Services Importer
The Advanced tab is the place where you can specify some additional (advanced indeed) options, such as the choice to map the XML Schema string type as a Pascal WideString (the default) or a regular Pascal LongString. You also have a choice to change the Base Class of the generated import unit.By default, this is TRemotable, and you should obviously only change this into something else if you know what you're doing.
Import Unit
Basically, all you have to do in the Web Services Importer wizard is specify the location of the WSDL and click on Generate to create the import unit.For our IEuro interface, the generated import unit can be seen in Listing 1 (saved in file Euro.pas):
unit Euro; interface uses Types, XSBuiltIns; type IEuro = interface(IInvokable) ['{2ACCD587-FF07-46B4-87BA-D590FF5C325A}'] function FromEuro(const Currency: WideString; const Amount: Double): Double; stdcall; function ToEuro(const Currency: WideString; const Amount: Double): Double; stdcall; end; implementation uses InvokeRegistry; initialization InvRegistry.RegisterInterface(TypeInfo(IEuro), 'urn:Euro-IEuro', ''); end.Note the GUID (the first line in the IEuro interface declaration), which wasn't necessary on the Linux side using Kylix 2, but is required using Delphi 6.
Web Service Consuming
Once you have an import unit, you can create a new project (any project will do, but let's build a "normal" Windows GUI project first), save the main form in MainForm.pas and the project itself in Euro42.dpr, and then add the import unit Euro.pas to its uses clause of the main form of this new project.On the main form, I want to design a Euro-calculator: converting a certain amount of money in one currency to another currency.The great advantage of only using the 12 Euro currencies is that we're certain that the conversion rates won't change (Euro conversions are fixed).The downside is that the Euro itself will be legal tender as of 1-1-2002, and the national currencies will be useless not too long after that.In other words: the lifespan of this web service will be limited, but that's OK, it's only an example (albeit a real-world one).
On our mainform, I want to show the 12 currencies, and convert a certain give amount either to Euros or from Euros.A problem is that I can't remember anymore which 12 currencies are involved with the Euro.And this is a deliberate point that I'm trying to make: although the WSDL describes the methods and parameters of a web service, it does nothing to explain the semantics or effects of certain argument and parameter values.If you look at the FromEuro and ToEuro methods, you'll notice that the first argument in both cases must be the Currency, a string that identifies the target or source currency.And to anyone who wants to consume my Euro web service, I must explain which potential values of Currency are valid.I've listed them below (see Listing 2):
const Finland = 'FIM'; Italy = 'ITL'; Netherlands = 'NLG'; Spain = 'ESP'; Belgium = 'BEF'; Austria = 'ATS'; Luxembourg = 'LUF'; Germany = 'DEM'; France = 'FRF'; Ireland = 'IEP'; Portugal = 'PTE'; Greece = 'GRO';Given these constants, I can fill a RadioGroup with the twelve strings.That will give the enduser the option of selecting one of the above mentioned currencies.
As you can see from Figure 3, apart from the RadioGroup (with the Columns property set to 3), I've used a TEdit for the input amount and a TEdit for the output (Readonly, no TabStop) as well as two buttons that will call the FromEuro and ToEuro methods.
HTTPRIO
This is the point where we actually start to use the web service.For that, we need a HTTPRIO component, which can be found on the Web Services tab.HTTPRIO stands for HTTP Remote Invokable Object (a remote object that we can invoke using only HTTP).
The HTTPRIO components needs the WSDL location again, assigned to the WSDLLocation property..And again, we can either specify the dynamic URL, or reference to a local file that stores the WSDL.Both will contain an actual reference where the web service can be found (in the service section of the WSDL document, that apart from the Service, also contains the Port and the soap:address which holds the location - using soap instead of wsdl).See listing 3
<service xmlns="http://schemas.xmlsoap.org/wsdl/" name="IEuroservice"> <port xmlns="http://schemas.xmlsoap.org/wsdl/" name="IEuroPort" binding="targetNamespace:IEurobinding"> <soap:address location="http://www.drbob42.co.uk/cgi-bin/Euro42/soap/IEuro"> </soap:address> </port> </service>So again you can either specify the IEuro42.wsdl or IEuro42.xml file here (that we saved last time), or specify the WSDL Location itself, namely http://www.drbob42.co.uk/cgi-bin/Euro42/wsdl/IEuro
unit MainForm;
interface
uses
Windows, Messages, SysUtils, Variants, Classes,
Graphics, Controls, Forms, Dialogs, Euro,
StdCtrls, ExtCtrls, Rio, SoapHTTPClient;
type
TForm1 = class(TForm)
RadioGroupCurrency: TRadioGroup;
BtnFromEuro: TButton;
BtnToEuro: TButton;
EditInput: TEdit;
EditOutput: TEdit;
HTTPRIO1: THTTPRIO;
procedure BtnFromEuroClick(Sender: TObject);
procedure BtnToEuroClick(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
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;
procedure TForm1.BtnToEuroClick(Sender: TObject);
begin
EditOutput.Text := FloatToStr(
(HTTPRIO1 AS IEuro).FromEuro(
RadioGroupCurrency.Items[RadioGroupCurrency.ItemIndex],
StrToFloat(EditInput.Text))) + ' EUR'
end;
end.
Note that I've added a postfix of the actual converted currency in both cases (in the FromEuro method, the postfix is made up of the current selected string in the RadioGroup, in the ToEuro method, the postfix is just the string with EUR itself).
Web Services and Efficiency
Kylix 2 Web Service Consumers
If you want to use Kylix 2 instead of Delphi 6 to build the Web Service client (consumer) then you need to change...nothing.Apart from the fact that a Kylix application is a CLX application, and we just build a VCL application (still the default in Delphi 6), there is no difference.In fact, I leave it as an exercise for the reader to build one (let me know if you're having problems, and I can send you the source code for a Kylix 2 consumer of the Euro42 web service).It's just that when using a Delphi 6 (on Windows) application to communicate with a Kylix 2 (on Linux) Web Service, you bring out the cross-platform nature of web services.Not the cross-language nature, yet (Delphi and Kylix both use Object Pascal), but we only have to wait a little while before JBuilder 6 ships with the Borland Web Services Toolkit for Java, which promises to create and consume web services that can also communicate with Delphi and Kylix.
And finally, you must remember that SOAP is still work in progress.And although it's nice for Delphi and Kylix to talk to each other, in the end much more environments on much more platforms should be able to talk with each other using Web Services and SOAP.And in order to check the interoperability of all these SOAP implementations, a special SOAP interoperability testing has been set up.Borland's efforts can be seen on the webpage at http://soap-server.borland.com/WebServices
It should be clear that SOAP, Web Services and their implementation in Borland development tools isn't finished, but has hardly started.We'll see lots of more SOAP in the future.I can promise you that! In the meantime, feel free to check out my website Dr.Bob's SOAP Bubbles at http://www.drbob42.com/SOAP
For more recent information on this topic, check out my Delphi 2010 XML, SOAP & Web Services courseware manual.