Do you remember that Delphi 6 was the first IDE in the market with Web Services support? This trend continues and Delphi 2009 supports building web service servers and clients:-) In this post I'm going to describe all steps neccessary to build simple web service server and client applications in Delphi 2009.
Building "Simple Calculator" web service application in Delphi 2009
The main difference between building ASP.NET web application and web services in Delphi 2007 and native web services in Delphi 2009 is that you have to manually create a virtual directory and physically deploy the web service application.
Creating a virtual directory
The first thing to do is to make sure that you have IIS installed. I'm currently using Windows XP. In default XP installation the IIS is not installed by default. In order to install it you need to go to "Add or Remove Programs" Control Panel aplet, click on the "Add/Remove Windows Components" and make sure that "Internet Information Services (IIS)" option is checked.
Once we know that IIS is installed, the second thing is to create a virtual directory for the web service application. This is done with "Internet Information Services" applet that you can find in Control Panel "Administrative Tools". Right click on the "Default Web Site" node and select "New | Virtual Directory" from the context menu.
This will launch "Virtual Directory Creation Wizard". Click on the "Next" button and enter the logical name of the virtual directory. For this example I'm going to name it "Delphi2009WS".
On the next screen you need to specify the physical directory. The default location for virtual folders is under "C:\Inetpub\wwwroot" so I have created a new "Delphi2009WS" directory there.
The last screen in the wizard is for specyfing access permissions to this virtual directory. Make sure to check "Execute (such as ISAPI applications or CGI)" option.
Creating a new "SOAP Server Application"
The ground work is done. Now it's time to start Delphi 2009 and create a new Web Service application. Double click "New SOAP Server Application" in "New Items" dialog available from "File | New | Other" menu.
This will launch the new web service application wizard. The first choice to make is how the application should be implemented.
I have selected to create a CGI application. This is the best type of application during the development because you do not have to restart the IIS every time you want to rebuild your application. Selecting "CGI" means that our application will be a Windows executable. This means that for every request to our web service application the IIS will have to execute our program. Launching a new OS process is an expensive operation, so in real life scenario it is better to implement web applications as ISAPI DLL, which is loaded once into the IIS process (inetinfo.exe) and stays there until the IIS is restarted.
But how do I convert CGI application into ISAPI/NSAPI library later? In fact the best solution is to add to a project group another Web Service server application, and go for ISAPI. In this way you will have two web service applications (one CGI and one ISAPI) in a Delphi project group and they can both share the same units that make up the web service application. Just add all the files from the CGI project to the ISAPI project. In this way every time you "build all" you will have both applications created with exactly the same logic. During development it is easier to use CGI, but at the end you will want to deploy as ISAPI DLL.
OK. Let's continue with the wizard. After selecting the application type the wizard will ask if we want to create the interface for the application.
Click on "Yes" and then the wizard will display "Add New WebService" dialog where you can specify service name and also service activation model ("per request" or "global"). I'm going to use the default "per request" activation model and enter "SimpleCalculator" as a name for the service. After clicking on the OK button the wizard will add three new units to the project. Click on "Save All" in the "File" menu. Accept default names for "SimpleCalculatorIntf" and "SimpleCalculatorImpl" units and save the third unit as "uWebModuleMain" and the whole project as "Delphi2009SimpleCalc". Delphi Project Manager will look something like this:
At this stage when we hit compile we will get a CGI executable file that is ready to be placed in the virtual directory. Of course we have not yet implemented any functionality. To make deployment easy we have two choices. You can save all units and project directly in the virtual folder physical directory. This is easy but not elegant. The better solution is to specify the "output" directory in the project options as our physical folder that we have used for virtual directory. In this way we will not "polute" the virtual folder with Delphi units and project files, but every time we compile Delphi automatically will put the resulting executable in the virtual directory.
If you are deploying on XP then you are done. The XP comes with IIS 5.1. There are also chances that you might want to deploy on Windows Server 2003 which comes with IIS 6. In this case you need to do one more step. In the "Internet Information Services" aplet there is additional node called "Web Service Extensions" where you need to explicitly add our web service executable to the list of binaries that are globally allowed to be executed.
Implementing web service logic
This is our next step – to implement methods in the web service that will be called by client applications. To keep this demo simple I'm only going to implement "Add" and "Subtract" methods that will accept two integers and return an integer.
All methods to be called by web service clients needs to be declared in the "interface" unit and then implemented in the "implementation" unit. Make sure to add "stdcall" to every method in the interface, because this is required by the underlying implementation.
The interface unit:
… and the implementation unit:
Compile project one more time and we are done. If you now open our web service test page in the browser you should see "Add" and "Subtract" method listed under "ISimpleCalculator" interface.
Somebody might ask: how this test page was generated? If you open the main web module of our application you will see that the wizard has added three components to the form.
These components are what makes this web application "a SOAP web service" application. In fact it would be also possible to start from plain "Web Server Application" (in "Delphi Projects – Web Broker" category) and add these components and units manually. The main web module to the Web Broker application is what is the main form in the VCL Forms application. Any request that arrive from HTTP clients are sent to WebModule actions. If the action matches the request path info and HTTP verb (here called "MethodType") than it is processed. In the case of a web service application all requests without any path info are processed with the default action called "DefaultHandler" that delegates processing to the "WSDLHTMLPublish1" component that is generating the test page on the fly.
It is often considered a good practice to change a default target namespace for SOAP messages that are exchanged between clients and servers to something different that http://tempuri.org/. This can be done via TWSDLHTMLPublish "TargetNamespace". I have changed the target namespace to http://demos.embarcadero.com
In order to be able to consume our web service we need to have a description of what our service do and where it can be found. This the role of the WSDL document that can obtained dynamically from running web service. If you click on the [WSDL] link on the test page next to the "ISimpleCalculator" service, you will see the contents of the WSDL that can be obtained via the "http://localhost/Delphi2009WS/Delphi2009SimpleCalc.exe/wsdl/ISimpleCalculator" URL, where the first part of the URL is the server where application is deployed (in my case "localhost"), the name of the virtual directory ("Delphi2009WS") and the name of the executable "Delphi2009SimpleCalc.exe". "/wsdl/ISimpleCalculator" is a logical path to a resource inside our web service application.
Building Delphi 2009 Web Service client application
At this stage we have a Delphi 2009 Simple Calculator web service application deployed to the IIS. The next step is to build a client for it. The easiest way of building a web service client is to run "WSDL Importer" wizard. Just create a new Delphi VCL Forms application, save all and double-click "WSDL Importer" wizard.
Note that the "New Items" dialog is context sensitive. When there was no active project the "Web Services" category contained "SOAP Server Application" only and now, when there is an active Delphi VCL Forms project in the IDE, it also contains "WSDL Importer" icon.
All you need to do is to enter a URL to the web service into the wizard and click "Next".
On the last screen of the wizard you can preview the contents of the proxy unit that wizard is going to add to the project.
When you click "Finish" the wizard will a new unit to the project with web service interface and one global function that returns a reference to the interface. In order to use the web service methods in code you can just call a generated "GetISimpleCalculator" function and access "Add" and "Subtract" methods.
The running client application looks like this:
Creating a client application without importing WSDL
If you look into the code generated by the "WSDL Importer" wizard you will notice that the definition of "ISimpleCalculator" interface is exactly the same like in the "SimpleCalculatorIntf" unit, that is a part of server project. In fact if the server and clients are both implemented in Delphi, then we could skip the "WSDL Importer" wizard and use the unit with interface definition in the client application. We will also need to use THTTPRIO component. In the wizard generated code this component is created dynamically and then it is typecasted into the interface.
Web Services as described in this post are only one of the method of doing client/server, or in general distributed computing, systems. Here we are using HTTP protocol for communication and SOAP protocol for exchanging XML messages.
Some feel that XML is too heavy and prefer to use JSON for communication. The HTTP protocol sits on top of the TCP protocol. RAD Studio 2009 introduced DataSnap 2009 architecture for building client and server applications that communicate using JSON and TCP protocol.
That's the subject to post about in the New Year 2009. Merry Christmas and a Happy New Delphi Year to all of You:-)
The source code for projects described in this post can be found at http://blogs.embarcadero.com/pawelglowacki/2008/12/18/38624.