Using services on the Server side

You have several methods to retrieve a TServiceFactory instance, either from the service name, its GUID, or its index in the list.

That is, you may code:

var I: ICalculator;
begin
  if Server.Services['Calculator'].Get(I)) then
    result := I.Add(10,20);
end;

or, for a a more complex service:

var CN: IComplexNumber;
begin
  if not Server.Services.Info(TypeInfo(IComplexNumber)).Get(CN) then
    exit; // IComplexNumber interface not found
  CN.Real := 0.01;
  CN.Imaginary := 3.1415;
  CN.Add(100,200);
  assert(SameValue(CN.Real,100.01));
  assert(SameValue(CN.Imaginary,203.1415));
end; // here CN will be released

You can of course cache your TServiceFactory instance within a local field, if you wish.

Client side

There is no implementation at all on the client side. This is the magic of mORMot's services: no Wizard to call (as in DataSnap), nor client-side methods to write - as with our method-based service implementation.

In fact, a hidden "fake" TInterfaceObject class will be created by the framework (including its internal VTable and low-level assembler code), and used to interact with the remote server. But you do not have to worry about this process: it is transparent to your code.

Set up the Client factory

On the client side, you have to register the corresponding interface, as such:

 Client.ServiceRegister([TypeInfo(ICalculator)],sicShared);

It is very close to the Server-side registration, despite the fact that we do not provide any implementation class here. Implementation will remain on the server side.

Note that the implementation mode (here sicShared) shall match the one used on the server side. An error will occur if this setting is not coherent.

The other IComplexNumber interface we talked about, is defined as such:

 Client.ServiceRegister([TypeInfo(IComplexNumber)],sicClientDriven);

To be more precise, this registration step is indeed not mandatory on the client side. If you use the TServiceContainerClient.Info() method, the client-side implementation will auto-register the supplied interface, in sicClientDriven implementation mode.

Using services on the Client side

Once the service is registered on the client side, it is very easy to use it in your code.

You can use the same methods as on the server side to retrieve a TServiceFactory instance.

That is, you may code:

var I: ICalculator;
begin
  if Client.Services['Calculator'].Get(I)) then
    result := I.Add(10,20);
end;

or, for a a more complex service, initialized in sicClientDriven:

var CN: IComplexNumber;
begin
  if not Client.Services.Info(TypeInfo(IComplexNumber)).Get(CN) then
    exit; // IComplexNumber interface not found
  CN.Real := 0.01;
  CN.Imaginary := 3.1415;
  CN.Add(100,200);
  assert(SameValue(CN.Real,100.01));
  assert(SameValue(CN.Imaginary,203.1415));
end; // here CN will be released on both client AND SERVER sides

You can of course cache your TServiceFactory instance within a local field, if you wish.

The code is just the same as on the server.
The only functional change is that the execution will take place on the server side (using the registered TServiceComplexNumber implementation class), and the corresponding class instance will remain active until the CN local interface will be released on the client.

As we stated in the previous paragraph, since the IComplexNumber is to be executed as sicClientDriven, it is not mandatory to call the Client.ServiceRegister method for this interface. In fact, during Client.Services.Info(TypeInfo(IComplexNumber)) method execution, the registration will take place, if it has not been done explicitly before. For code readability, it may be a good idea to explicitly register the interface on the client side also, just to emphasize that this interface is about to be used, and in which mode.

Continue reading...

This article is part of a list of other blog articles, extracted from the official Synopse mORMot framework documentation:

Feedback and questions are welcome on our forum, just as usual.