Calling a service method from inside the server?

I have a server an plan to call a service method from the save server. Is possible? Using delphi.

1 Like

Hello,

Yes, this is possible.
To call service method from server you need to create service instance:

var fClassFactory: IROClassFactory;
ClientID : TGUID;
instance: IInterface;
begin
ā€¦
ClientID:=ROBinMessage.ClientID;
fClassFactory:=GetClassFactory(ā€˜YourServiceā€™);
fClassFactory.CreateInstance(ClientID, instance);
(instance as IYourService).YourMethod;
ā€¦
end;

Best regards

1 Like

Works like a charm. Best regards.

Found this after hitting the same problem but thereā€™s something I donā€™t understand.

The TROClassFactory.CreateInstance method doesnā€™t appear to do anything with the supplied ClientID. After I use the above code to create an instance of a service class, the fSession property is NIL because itā€™s never set.

Where am I going wrong?

Digging around a bit in the source, it appears that more needs to be done that the above code snippet.

The BeforeInvoke and AfterInvoke methods of TROInvoker are calling the OnActivate and OnDeactivate methods of the service which are declared in IROObjectActivation. It seems it is this OnActivate methods which is actually assigning the relevant session object to the fSession property of the service.

These functions are obviously called as part of a service invokation from a client but not in the code above. Can you please elaborate on the correct way to achieve this locally on the server? Iā€™m tempted to simply assign the session object to the service manually but not sure if this is the right thing to do (or even possible).

Hello,

you need to consider if session handling is necessary for local call from inside the server. If yes, see TROLocalChannel/TROLocalServer component pair, it may be solution for you. In this case, method calls are processed in ā€œremoteā€ manner, service is created by factory, activated/deactivated by invoker, so session is found & set correctly inside the TRORemoteDataModule.DoOnActivate method. As a drawback of this solution, during each service invocation, methods and its parameters are fully serialized and marshalled through relevant ROMessage, which can slown down executing of service methods.

If you donā€™t need to use session handling, the way advised by elenap is sure better one.

See code inside the uROServer.TROInvoker.CustomHandleMessage method, details about service invocation are pretty shown here.

Greetings
Jaroslav

ā€¦if you have license of RemObjects Hydra, see and consider THYLocalService component to use it for your purpose. This component solve (in a bit compromise way) need of local service invocation without overhead of message serialization, alongside need of session finding & set before service method processing.

Greetings,
Jaroslav

Thanks, Iā€™ll look into these options.

Out of interest, how does the TROLocalChannel/TROLocalServer solution compare with the suggested solutions in this topic?: What's the best/recommended way to access service functions server-side

As mentioned above, server method invocation by TROLocalChannel/TROLocalServer works in ā€œremoteā€ manner, almost in the same way as other traditional network-aware channels works. You need to have ā€œclientā€ components (TROLocalChannel + TROxxxMessage), as well as ā€œserverā€ components (TROLocalServer + TROxxxMessage) in your application. TROLocalChannel component has ServerChannel property, it must be attached directly to TROLocalServer component.

Service needs to be referenced using proxy class, which can be gathered either with TRORemoteService component:

RemoteService.Channel:=LocalChannel;
RemoteService.Message:=BinMessage;
MyService:=RemoteService as IMyService

or manually, using

MyService:=CoMyService.Create(LocalChannel,BinMessage)

eventually

MyService:=TMyService_Proxy.Create(LocalChannel,BinMessage)

Calling service methods through proxy class brings the overhead of serialization, but it fully respects all usual processing rules, ensures that all essential steps will be processed, including session location and assignment.

Calling service method directly, through manually created instance, has (of course) the benefit of speed, there is no overhead of serialization, however, processing rules are ignored, essentials steps must be processed explicitly, before and after every service method call.

Consider yourself what is better solution for you

See this for another details:
http://wiki.remobjects.com/wiki/TROLocalChannel_Class
http://wiki.remobjects.com/wiki/TROLocalServer_Class

Greetings,
Jaroslav

Hello,
Try to use the code like this:

function TFirstService.GetServerTime: DateTime;
var
cf: IROClassFactory;
instance: IInterface;
objactivation:IROObjectActivation;
begin
cf:=GetClassFactory(ā€˜SecondServiceā€™);
cf.CreateInstance(ClientID, instance);

if Supports(instance, IROObjectActivation, objactivation) then
begin
objactivation.OnActivate(ClientID, nil);
end;

Result := (instance as ISecondService).GetServerTime();

if Supports(instance, IROObjectActivation, objactivation) then
begin
objactivation.OnDeactivate(ClientId);
end;

instance := nil;
end;