Question about a DA Server as a Windows Service?

Hi,

I have a custom DA server written in Delphi with some exposed methods. That is working fine. But i need to setup a timer inside the Windows Service itself that when fired calls one of the exposed methods. Is this possible? and if so, what’s the recommended way to do this?

Regards,

Why do you want to put a timer???

Maybe a new service, acting as a client, separate to the DA server? A windows service with a timer & delay to call external method in the DA Service would be fairly easy to implement. HTH - Stu

Hello,

If I understand right, you have DA server that implemented as Windows service and you need to invoke some of your service methods from the server in onTimer event?

If so, you could drop timer component on you TService form and in order to call service method from server you need to create service instance in onTimer event:

procedure TService1.Timer1Timer(Sender: TObject); var fClassFactory: IROClassFactory; ClientID : TGUID; instance: IInterface; begin [...] ClientID:=ROBinMessage.ClientID; fClassFactory:=GetClassFactory('YourService'); fClassFactory.CreateInstance(ClientID, instance); (instance as IYourService).YourMethod; [...] end;

Hope this helps

Elenap,

[...] ClientID:=ROBinMessage.ClientID; fClassFactory:=GetClassFactory('YourService'); fClassFactory.CreateInstance(ClientID, instance); (instance as IYourService).YourMethod; [...]

In my case I am using PooledClassFactory, how to get an instance (previously created) from other service ??

Thanks,
Willian

Hello,

In my case I am using PooledClassFactory, how to get an instance (previously created) from other service ??

When you call
fClassFactory.CreateInstance(ClientID, instance);
and fClassFactory is a TROPooledClassFactory object it returns to you first service instance fom the pool that is not used.

Read also about PerClientClassFactory, maybe it suits you too Documentation | RemObjects Software

Hope this helps

elenap,

thanks worked, but two points:

I didn´t find the method getPooledClassFactory to use with IROPooledClassFactory … But using IROClassFactory with getClassFactory worked even if my service is TROPooledClassFactory; ok?

needed to explicitly release instance with:

fClassFactory.ReleaseInstance(ClientID,instance);

Without it, pool get messed …

Read also about PerClientClassFactory, maybe it suits you too Documentation | RemObjects Software

Hope this helps

I used it in the past but that does not scale as well as ClassFactory…

Thanks,
Willian.

Hello,

I didn´t find the method getPooledClassFactory to use with IROPooledClassFactory … But using >IROClassFactory with getClassFactory worked even if my service is TROPooledClassFactory; ok?

Yes, it will works, cause all the types of class factories implement IROClassFactory interface.

needed to explicitly release instance with:

fClassFactory.ReleaseInstance(ClientID,instance);

You are right, instance should be released.

Best regards

elenap,

ClientID:= ROBinMessage.ClientID;
fClassFactory:=GetClassFactory('YourService');
fClassFactory.CreateInstance(ClientID, instance);
(instance as IYourService).YourMethod;

Not working with Sessions;

Inside: (instance as IYourService).YourMethod; TRORemoteDataModule.fSession is nil and it create another session when using property Session.

as workaround I did this:

procedure TYourService.YourMethod;

var Session : TROSession;

begin

// use Session as local variable
Session := SessionManager.FindSession(ClientID);


end;

but of course this does not work if I call another method (from YourMethod), and again uses Session …

How can I assign property Session (read only) to my service before executing instance.YourMethod ?

Thanks,
Willian.

Hello,

willian_cslog said: Not working with Sessions;

Inside: (instance as IYourService).YourMethod; TRORemoteDataModule.fSession is nil and it create another session when using property Session.

Working with sessions in RO is inseparable linked with using of Login service. Read more Documentation | RemObjects Software . So you need to login first and after that read-only Session property will be assigned. I suppose that you do login from client and then want to call service method from server with saved clientId. In that case you should change:
ClientID:=ServerDataModule.Message.ClientID;
to ClientID of necessary client (get it from SessionManager)

And you should add at the beginning of every service method you want to call from server your workaround:

procedure TYourService.YourMethod;

var Session : TROSession;

begin

// use Session as local variable
Session := SessionManager.FindSession(ClientID);


end;

But you could also use Local channels in your case. Drop TROLocalServer and TROLocalChannel components on service form (TService1 for example), fill necessary properties and call service methods in such a way:

var log: ILoginService;
serv:IDataService;
usInfo: UserInfo;
begin
log:=CoLoginService.Create(ROMessage, ROLocalChannel1);
b:=log.Login(userId,Password,UsInfo);
serv:=CoDataService.Create(ROMessage, ROLocalChannel1);
serv.YourMethod;
end;

Hope this helps

elenap,

I suppose that you do login from client and then want to call service method from server with saved clientId.

Yes !!

In that case you should change: ClientID:=ServerDataModule.Message.ClientID; to ClientID of necessary client (get it from SessionManager)

Not worked using JSONMessage Message.ClientID is returning another ClientID ! … Now I am passing ClientID as parameter to my service method:

procedure TYourService.YourMethod (MyClientID : GUID);

var Session : TROSession;

begin

ClientID := StringToGUID(MyClientID);
Session := SessionManager.FindSession(ClientID);


end;

Not elegant, but worked for me… not tried to use local channel because using it I need to authenticate twice (one from client, and another from server) …

Thanks,
Willian.

Hello Willian,

Not worked using JSONMessage Message.ClientID is returning another ClientID ! ... Now I am passing ClientID as parameter to my service method:

This is a quite tricky way, messages are being cloned during request processing to enforce thread safety. Actually the message component dropped to the server data module acts as a message settings storage and that instance is not actually used.

not tried to use local channel because using it I need to authenticate twice (one from client, and another from server) ...

Using the local channel seems to be the most straightforward solution for you. You need not to authenticate twice. Once you have a ClientID (aka SessionID) that is logged in you can save it and use for the communication via local channel. Just assign this ClientID to the message instance that is used with local channel.

Best regards - Sergey.