About this Article Article

This article covers the following platforms

Delphi |  Kylix

More Articles about RemObjects SDK

RO00 - Article ROadmap for the...

RO01 - RemObjects SDK Overview

RO04 - Mega Demo

RO05 - How to Write a RemObjects SDK...

RO06 - How to Write a RemObjects SDK...

RO07 - Smart Services™

RO08 - Smartening our First Server

RO09 - RemObjects 2.0 Session Managers

RO10 - Stop Calling Me So Often:...

RO11 - Building Asynchronous Clients...

RO12 - Consuming an Existing SOAP Based...

RO13 - Smart Project: Creating Scalable...

RO14 - Introducing the DiscoveryClient...

RO15 - Behind the Scenes: Inside...

RO16 - Class Factories Overview

RO17 - Manipulation of RODL Meta Data

RO18 - RODL - The Service Description...

RO19 - DataSnap Integration Pack

RO20 - How to Write a Service Using...

RO21 - Simple DataSnap Servers without...

RO24 - Creating Custom Project Templates

RO25 - Understanding the Client Side

RO27 - RemObjects 3.0 SDK Preview

RO28 - Using RemObjects SDK from COM

RO29 - Using the Service Tester

RO31 - Code level features of the...

RO33 - SSL/TLS for RemObjects SDK

RO34 - I Cannot ROmember

RO35 - ROCalc service

RO36 - Multicast Events in RemObjects...

RO37 – The New Super Channels

RO38 - Comparison of the RemObjects SDK...

RO39 - Applying updates to multiple...

RO40 - Support for XML-RPC

RO41 - Update standard .NET event...

RO42 - Introduction to Free Pascal...

RO45 - How to Write a RemObjects SDK...

RO46 - How to Write a RemObjects SDK...

WP02 - Cross Platform Development with...

Articles for this product are grouped in:

Ready for 'Vinci'

Introduction

First Steps

Smart Services

Interoperability

Architecture

Intermediate

Advanced

Tools

Contributions

DataSnap

Whitepaper

Update Pending

Legacy

Search Articles


Advanced Search...

RO13 - Smart Project: Creating Scalable Smart Services™ with the RemObjects SDK

by Nathanial Woolls

Note from RemObjects: although we believe the content of this article to be correct, we do not warrant that it is so. We thank Nate very much for producing this, which we are pleased to publish here.

This tutorial will provide you with the steps needed to create your own RemObjects 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 RemObjects’ highly efficient BIN message format, and transferring data using the same ISAPI service project as a local dynamic link library.

New RemObjects ISAPI Service

After starting Delphi , click on "File|New|Other", which will open the "New Project" dialog. Select the "RemObjects SDK" tab and select the "ISAPI/NSAPI Server Project" item:

Click the “OK” button.   You will now be prompted with the “RemObjects ISAPI/NSAPI Server Project” settings dialog. Fill in the values found below:

You will now be presented with your new RemObjects service project, SmartProject. The project contains a single WebModule, with a TROSOAPMessage and TROWebBrokerServer. This is the standard start of a RemObjects ISAPI service:

Navigate the Delphi main menu to click "RemObjects|Service Builder", which will display the RemObjects Service Builder, an IDE for creating your Smart Service. This is where you will spend your time designing your RemObjects Services:

Click to
  view full size screenshot
Click to view full size screenshot

New RemObjects 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 RemObjects precompiler will generate the necessary units for your Web Service (and regenerates those units, except for your implementation unit, whenever your service is recompiled):

Click to view full size
  screenshot
Click to view full size screenshot

 

Now, you should 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 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 RemObjects (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 RemObjects' 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, RemObjects comes with components out of the box that allow you to scale your Web Service to support, along with SOAP, a highly efficient BIN messaging protocol. The BIN protocol has support for 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 RemObjects 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 for us, 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 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. RemObjects 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. RemObjects 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!

RemObjects 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 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 seen below (new code is in blue):

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 to see 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 (new code is in blue):

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 even handlers to use our new GetChannel() method to retrieve an appropriate RO Channel object for our given location. Run the program and try it!

Consuming your Smart Service™ in Microsoft C#

After the Visual Studio IDE is loaded,click "File|New|Blank Solution". Select the "Visual C# Projects" folder and the "ASP. NET Web Application" item. Fill out the dialog as show below:

Click the "OK" button. Design a form similar to the one below, with a TextBox, two Buttons, and an output Label.

Right click on the "References" folder in the "Solution Explorer" window and click "Add Web Reference". Fill in the SOAP URL for your Smart Service and click the "Go" button.

 

Click the "Add Reference" button. Add the following event handlers to your two Buttons:

private void Button1_Click( object sender, System.EventArgs e)
 {
       localhost.SmartServiceService SmartSrvc;
       SmartSrvc = new localhost.SmartServiceService();
       ResultLabel.Text = "1 + 2 = " + SmartSrvc.Sum(1, 2).ToString();
 }
private void Button2_Click( object sender, System.EventArgs e)
 {
       localhost.SmartServiceService SmartSrvc;
       DateTime ServTime ;
       SmartSrvc = new localhost.SmartServiceService();
       ServTime = SmartSrvc.GetServerTime();
       ResultLabel.Text = ServTime.ToString();
 }

Notice that the imported WSDL information allows for code completion within the Visual Studio. NET IDE:

Now we are ready to test our C# web application. Click the "Run" toolbar button within the VS. NET IDE.

Simply Scalable

As you've seen, RemObjects SDK enables you to serve your business objects from anywhere, scaling from a local library, to a standard Web Service, to 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.