Smart Project - Creating Scalable Smart Service (Delphi)
This tutorial will provide you with the steps needed to create your own Remoting Smart Service™, capable of serving your business logic via the standard mechanisms of SOAP over HTTP, while also exposing your service in a variety of other ways, including Remoting’ highly efficient BIN message format, and transferring data using the same ISAPI service project as a local dynamic link library.
See article Smart Project - Creating Scalable Smart Service (.NET) for the Delphi edition.
New Remoting ISAPI Service
After starting Delphi, click on File -> New -> Other
, which will open the New Project
dialog. Select the Remoting SDK
tab and then select the ISAPI/NSAPI Server Project (RODL-based)
item:
Click the OK
button. You will now be prompted with the Remoting ISAPI/NSAPI Server Project
settings dialog. Fill in the values below:
You will now be presented with your new Remoting service project – SmartProject. The project contains a single WebModule with a TROSOAPMessage and TROWebBrokerServer. This is the standard start of a Remoting ISAPI service:
Navigate the Delphi main menu to click Tools -> Remoting SDK -> Service Builder
, which will display the Remoting Service Builder, an IDE for creating your Smart Service. This is where you will design your Remoting Services:
New Remoting Services come with two sample methods, Sum() and GetServerTime(), which we will be implementing in this tutorial.
Now, navigate the Delphi main menu and click Project|Options
. In the Project Options
dialog, click the Directories/Conditionals
tab and enter your ISAPI folder in the Output directory
field. Click the OK
button.
Assuming you already have OnCompile Helpers installed, click Project|OnCompile Helpers|COM+|Manage COM+ Applications
.
In the Manage COM+ Applications & Services
dialog, select the COM application that corresponds with your ISAPI folder and click the Set as Debug Host
button. This will display the Run Parameters
dialog, populated with the values needed to run and debug your ISAPI Service within the Delphi IDE. Click the OK
button.
Click the Run
toolbar button in the Delphi IDE. The Remoting precompiler will generate the necessary units for your Web Service (and regenerate those units, except for your implementation unit, whenever your service is recompiled):
You should now be able to open Internet Explorer and browse to your ISAPI Web Service. Mine, for instance, is accessible through http://localhost/isapi/SmartProject.dll/SOAP. This should show you the Web Service Description Language (WSDL) document for your new service.
Return to your project and open the implementation file for your project. This should be SmartService_Impl.pas. Add SysUtils to your uses clause and complete the implementation code for the Sum() and GetServerTime() methods (new code is represented in blue):
function TSmartService.Sum( const A: Integer; const B: Integer): Integer;
begin
Result := A + B;
end ;
function TSmartService.GetServerTime: DateTime;
begin
Result := Now;
end ;
Compile your service after completing these methods. You now have a fully functional standard Web Service, serving your logic over HTTP via SOAP.
Consuming your Web Service
Right-click on your Project Group in the Project Manager
and click the Add New Project
menu item. Select the New
tab and the Application
item.
Click the OK
button. Design your form similarly to the one below, including a TEdit, two TButtons, a TROSoapMessage, and a TROWinInetHTTPChannel. The soap message component will be used to communicate with our Web Service and the WinInet channel is one of many HTTP channels provided out of the box with Remoting (WinInet is Windows specific, but also more flexible than the other HTTP channels).
Right-click on your new Application in the Project Manager
and click the Add
menu item. Select the interface source file from your service. This should be SmartLibrary_Intf.pas. You could also generate this file via your service's published WSDL document using Remoting' Service Importer, but this solution is easiest when you are authoring both the service and the client. Hit the ALT+F11 keys, which will display the Use Unit
dialog. Add the SmartLibrary_Intf
unit to your uses and click the OK
button:
Add the following event handlers for the Add
and Get Time
buttons:
procedure TForm2.Button1Click(Sender: TObject);
begin
ROWinInetHTTPChannel1.TargetURL := Edit1.Text;
with CoSmartService.Create(ROSOAPMessage1, ROWinInetHTTPChannel1) do
ShowMessage(IntToStr(Sum(1, 2)));
end ;
procedure TForm2.Button2Click(Sender: TObject);
begin
ROWinInetHTTPChannel1.TargetURL := Edit1.Text;
with CoSmartService.Create(ROSOAPMessage1, ROWinInetHTTPChannel1) do
ShowMessage(DateTimeToStr(GetServerTime));
end ;
Now, run your client application. Put the address of your Web Service in the edit box, and try the Add
and Get Time
buttons.
We now have a fully functional client for our Web Service.
Scaling your Web Service to a Smart Service™
While our Web Service works quite well, Remoting comes with out of the box components that allow you to scale your Web Service to support, along with SOAP, a highly efficient BIN messaging protocol. The BIN protocol supports both encryption and compression and results in up to 80 compression over standard SOAP. A Smart Service can support both SOAP and BIN messaging protocols very easily. Let's see how:
In the Project Manager
, activate your SmartProject service project. Activate your WebModule and add a TROBinMessage, renaming your components as shown below (for readability):
Click the button in the Dispatchers property editor for the ROServer component. This dialog displays the message dispatchers for the current RO Server object. You should already see one entry for your SOAPMessage component.The Path Info
field indicates the trailing URL path associated with the given RO Message object. If you recall, we’ve been accessing our Web Service through http://localhost/isapi/SmartProject.dll/SOAP (or similar), which has told our RO Server object to use the ROSOAPMessage object to handle message parsing. Click the Add
button and select the BINMessage component in the Message
combo box. The dialog will automatically fill in your Path Info
text box with BIN
, but you may edit this if you desire.
Now, simply recompile your SmartProject service. Your Web Service is now a Smart Service™, ready to serve clients via either the standard SOAP over HTTP or the more efficient BIN over HTTP for Remoting enabled clients.
Consuming your Smart Service™
In the Delphi Project Manager, activate your client application. Activate your main form, and remove the SOAP Message component. Click File|New|Unit
, save the unit as ROFuncs.pas and fill in the code below. Note that this is simply providing a function to generate an RO Message object, either SOAP or BIN, depending on the Location
parameter:
unit ROFuncs;
interface
uses uROClient, uROProxy;
function GetMessage(Location: string ): TROMessage;
implementation
uses SysUtils, uROBINMessage, uROSOAPMessage, Classes;
function GetMessage(Location: string ): TROMessage;
begin
if (Length(Location) > 3) and
(UpperCase(Copy(Location, Length(Location) - 3, 4)) = '/BIN') then
begin
Result := TROBINMessage.Create( nil );
TROBINMessage(Result).UseCompression := True;
end else
begin
Result := TROSOAPMessage.Create(TComponent( nil ));
end ;
end ;
end ;
Activate your main form and hit ALT+F11 to display the Use Unit
dialog. Add the ROFuncs
file to your uses and click the OK
button.
Now, alter the event handlers for your buttons as shown below (new code is represented in blue):
procedure TForm2.Button1Click(Sender: TObject);
var
ROMsg: TROMessage;
begin
ROWinInetHTTPChannel1.TargetURL := Edit1.Text;
ROMsg := GetMessage(Edit1.Text);
try
with CoSmartService.Create(ROMsg, ROWinInetHTTPChannel1) do
ShowMessage(IntToStr(Sum(1, 2)));
finally
ROMsg.Free;
end;
end ;
procedure TForm2.Button2Click(Sender: TObject);
var
ROMsg: TROMessage;
begin
ROWinInetHTTPChannel1.TargetURL := Edit1.Text;
ROMsg := GetMessage(Edit1.Text);
try
with CoSmartService.Create(ROMsg, ROWinInetHTTPChannel1) do
ShowMessage(DateTimeToStr(GetServerTime));
finally
ROMsg.Free;
end;
end ;
Compile and run your application. Now, for your service location, you can either indicate a trailing /SOAP
to access your Smart Service via the SOAP protocol, or /BIN
to access it via the BIN message protocol. Remoting seamlessly takes care of the rest.
Scaling back your Smart Service™
Having a central service for business logic is essential in today's business world. However, the technical market is far from shunning the need to have a local application. While more and more people are equipped with Internet connections, many clients still require a local solution. Remoting Smart Services can fill this gap, too, with only a few lines of code. This means that you can use the exact same code base for your ISAPI Smart Service, your local dynamic link library Smart Service, and your standards-compliant SOAP Web Service. They are all the same file.
Remoting has a built-in wizard for creating a local link library service as easily as our ISAPI service. However, because we want to adapt our existing ISAPI service to function as a local service as well, we need to add a few lines of code to our SmartProject. In the Delphi Project Manager
, activate your SmartProject service. Right click on the SmartProject.dll
project node and click the View Source
menu item. Add uRODLLServer, uROBINMessage and Windows to your project's uses clause. Add the following code (new code is represented in blue):
var BINMessage : TROBINMessage;
procedure ROProc(Reason:integer);
begin
case Reason of
DLL_PROCESS_ATTACH: begin
BINMessage := TROBINMessage.Create( NIL );
RegisterMessage(BINMessage);
end ;
DLL_PROCESS_DETACH: begin
BINMessage.Free;
end ;
end ;
end ;
exports
GetExtensionVersion,
HttpExtensionProc,
TerminateExtension;
begin
DLLProc:=@ROProc;
ROProc(DLL_PROCESS_ATTACH);
CoInitFlags := COINIT_MULTITHREADED;
Application.Initialize;
Application.CreateForm(TMainModule, MainModule);
Application.Run;
end .
Recompile your service. Your service is now ready to serve either via HTTP or as a local dynamic link library. Let's expand on our client application and try it out.
Consuming a local Smart Service™ Library
In the Delphi Project Manager
, activate your client application project. Open the RUFuncs.pas file in the Delphi editor. Add uROWinInetHTTPChannel and uRODLLChannel to the ROFuncs uses clause. Add the following GetChannel() function and alter the existing GetMessage() function, as shown below:
function GetChannel(Location: string ): TROTransportChannel;
function GetMessage(Location: string ): TROMessage;
implementation
uses uROWinInetHTTPChannel, uRODLLChannel, SysUtils, uROBINMessage, uROSOAPMessage, Classes ;
function GetChannel(Location: string ): TROTransportChannel;
begin
if (FileExists(Location)) and (UpperCase(ExtractFileExt(Location)) = '.DLL') then
begin
Result := TRODLLChannel.Create( nil );
TRODLLChannel(Result).DLLName := Location;
end else
begin
Result := TROWinInetHTTPChannel.Create( nil );
TROWinInetHTTPChannel(Result).TargetURL := Location;
end ;
end ;
function GetMessage(Location: string ): TROMessage;
begin
if (FileExists(Location)) and (UpperCase(ExtractFileExt(Location)) = '.DLL') then
begin
Result := TROBINMessage.Create( nil );
TROBINMessage(Result).UseCompression := True;
end else
begin
if (Length(Location) > 3) and
(UpperCase(Copy(Location, Length(Location) - 3, 4)) = '/BIN') then
begin
Result := TROBINMessage.Create( nil );
TROBINMessage(Result).UseCompression := True;
end else
begin
Result := TROSOAPMessage.Create(TComponent( nil ));
end;
end;
end;
Now we have a function that will return an RO Channel object depending on the Location
parameter, and we have adapted our GetMessage() function to check if a local library file is passed as the Location
parameter. Activate your main form and remove the WinInet Channel component. Alter your event handlers as follows:
procedure TForm2.Button1Click(Sender: TObject);
var
ROMsg: TROMessage;
ROChannel: TROTransportChannel;
begin
ROMsg := GetMessage(Edit1.Text);
ROChannel := GetChannel(Edit1.Text);
try
with CoSmartService.Create(ROMsg, ROChannel) do
ShowMessage(IntToStr(Sum(1, 2)));
finally
ROMsg.Free;
ROChannel.Free;
end;
end;
procedure TForm2.Button2Click(Sender: TObject);
var
ROMsg: TROMessage;
ROChannel: TROTransportChannel;
begin
ROMsg := GetMessage(Edit1.Text);
ROChannel := GetChannel(Edit1.Text);
try
with CoSmartService.Create(ROMsg, ROChannel) do
ShowMessage(DateTimeToStr(GetServerTime));
finally
ROMsg.Free;
ROChannel.Free;
end;
end;
We have simply altered our event handlers to use our new GetChannel() method to retrieve an appropriate RO Channel object for our given location. Run the program and try it.
Simply Scalable
As you've seen, Remoting SDK enables you to serve your business objects from anywhere, scaling from a local library to a standard Web Service or a highly efficient Smart Service™, all with just a few lines of code. Creating a truly scalable framework for your applications has never been easier.