Migrating from a DataSnap application to Data Abstract (Delphi)

In this article will be shown how to migrate from Datasnap applications to DataAbstract application.

testcase.zip

Server-side

This datasnap server uses authentication, provides access to Customer table from Employee.gdb and allows to call custom server methods. so DataAbstract server will contain two services: LoginService that will check authentication and DataService that will be main service.

Creating Server.RODL in Service Builder

It can be made via Remoting SDK & Data Abstract->Turn server into a Remoting SDK Server (RODL Based)

after confirmation, Service Builder will be launched. For correct work, these two services should be created as descendants of base Data Abstract services. For this, DataAbstract4.RODL should be imported into server.RODL:

After this, two new services should be created: Loginservice with SimpleLoginService as the ancestor and DataService with DataAbstractService as the ancestor. Also create two operations in DataService:

function EchoString(Value: WideString): WideString;
function ReverseString(Value: WideString): WideString;

Close Service Builder.

Generation of files from RODL

Call Remoting SDK & Data Abstract->Regenerate Units from RODL. These files will be generated:

  • NewLibrary_Intf.pas
  • NewLibrary_Invk.pas
  • LoginService_Impl.pas
  • DataService_Impl.pas

ServerDataModule.pas

Create a new datamodule and drop to it:

set this value in Object Inspector: DAConnectionManager1.DriverManager = DADriverManager1 Click on ROIndyHTTPServer1.Dispatchers in ObjectInspector and add new dispatcher

also create onCreate event:

procedure TDataModule1.DataModuleCreate(Sender: TObject);
begin
  ROIndyHTTPServer1.Active := True;
end;

LoginService_Impl.pas

Select LoginService_Impl.pas.

Add ServerDataModule into uses section and set in Object Inspector:

LoginService.SessionManager = ServerDM.ROInMemorySessionManager1. 

Two events are required in this unit:

procedure TLoginService.SimpleLoginServiceLogin(Sender: TObject; aUserID,
  aPassword: String; out aUserInfo: UserInfo;
  var aLoginSuccessful: Boolean);
begin
  aLoginSuccessful := (aUserID <> `) and (aUserID = aPassword);
  if aLoginSuccessful then CreateSession;
end;

procedure TLoginService.SimpleLoginServiceLogout(Sender: TObject);
begin
  DestroySession;
end;

DataService_Impl.pas

Select DataService_Impl.pas, drop

set properties in ObjectInsector:

DataService.ServiceDataStreamer = DABin2DataStreamer1
DataService.ServiceSchema = DASchema1
DataService.SessionManager = ServerDM.ROInMemorySessionManager1
DataService.RequiresSession = True
DASchema1.ConnectionManager = ServerDM.DAConnectionManager1

copy content of these methods from ServerMethodsUnit1.pas:

function TDataService.EchoString(const Value: UnicodeString): UnicodeString;
begin
  Result := Value;
end;

function TDataService.ReverseString(const Value: UnicodeString): UnicodeString;
begin
  Result := StrUtils.ReverseString(Value);
end;

Dbl click on DASchema1, Schema Modeler will be launched.

create a new connection to Employee.gdb and CUSTOMER table:

Close Schema Modeler.

Compile and launch server.

Server-side is ready now.

Client-side

Client side contains login/logout buttons, grid that shows table and two buttons which call custom servers methods.

Select client.dpr and add NewLibrary_Intf.pas from server project to client.dpr

ClientDataModule.pas

Add a new datamodule via wizard (New->Other->Data Abstract->Client module for VCL application) or perform some actions manually, like:

Drop

and set properties in Object Inspector:

ROWinInetHTTPChannel1.TargetURL = http://localhost:8099/bin
RORemoteService1.Channel = ROWinInetHTTPChannel1
RORemoteService1.Message = ROBinMessage1
RORemoteService1.ServiceName = DataService
DARemoteDataAdapter1.DataStreamer = DABin2DataStreamer1
DARemoteDataAdapter1.RemoteService = RORemoteService1
DARemoteDataAdapter1.ReconcileProvider = DAVCLReconcileProvider1

click on "Create Data Tables..." in popup menu of DARemoteDataAdapter1. Login Screen will be shown, type UserID=test;Password=test in aLoginString and create CUSTOMERS table in next dialog.

MainForm.pas

Add NewLibrary_intf and ClientDataModule into uses section. Replace old methods in MainForm:

procedure TForm2.Button1Click(Sender: TObject);
begin
  DataModule1.tbl_CUSTOMER.Close;
  DataModule1.tbl_CUSTOMER.Open;
end;

procedure TForm2.Button2Click(Sender: TObject);
begin
  DataModule1.tbl_CUSTOMER.ApplyUpdates;
end;

procedure TForm2.Button3Click(Sender: TObject);
begin
  ShowMessage((DataModule1.RORemoteService1 as IDataService).EchoString(Edit3.Text));
end;

procedure TForm2.Button4Click(Sender: TObject);
begin
  ShowMessage((DataModule1.RORemoteService1 as IDataService).ReverseString(Edit3.Text));
end;

procedure TForm2.Button5Click(Sender: TObject);
begin
 if not CoLoginService.Create(DataModule1.ROBinMessage1,DataModule1.ROWinInetHTTPChannel1).LoginEx(
     UTF8Encode(Format('UserID=%s;Password=%s',[Edit1.Text,Edit2.Text]))) then
   showMessage('Problems with login');
end;

procedure TForm2.Button6Click(Sender: TObject);
begin
  DataModule1.tbl_CUSTOMER.Close;
  CoLoginService.Create(DataModule1.ROBinMessage1,DataModule1.ROWinInetHTTPChannel1).Logout;
end;

Client side is ready.

P.S. Don't forget to remove old datasnap units from projects

testcase.zip