0
votes

I'm running some Datasnap tests with REST and json.

There in Unit ServerMethods, which Delphi itself creates, has the "ReverseString" function, but well, how do I know who sent it?

I would like to keep a log of information from the clients who called this method.

I know it could be passed as a parameter, but it would be the responsibility of the client to pass this information to me, which I do not want, let's say the method would be public and several clients would be triggering this information. I can easily lose this control, if I do not get the information directly by the control of the server.

I found on the web, that in the ServerConteiner unit, has a "DSServer" object, this object has an event called "OnConnect", so it can get the following sa data:

Procedure TServerContainer1.DSServer1Connect (
  DSConnectEventObject: TDSConnectEventObject);
Begin
  DSConnectEventObject.ChannelInfo.ClientInfo.IpAddress;
  DSConnectEventObject.ChannelInfo.ClientInfo.ClientPort;
  DSConnectEventObject.ChannelInfo.ClientInfo.Protocol;
  DSConnectEventObject.ChannelInfo.ClientInfo.AppName;
End;

But I am not able to find how there in ServerMethods.ReverseString I can get this data ...

I believe that the processing is in thread on the server, so I can not pass this value as global, because it can pick up information from other simultaneous connections.

In the method, ReverseString, I tried as follows:

Var
    ADSServerClass: TDSServerClass;
Begin
  ADSServerClass: = TDSServerClass (GetOwner);
  TDSServer (ADSServerClass.Server). ???
  // I got to the server, but I can not find it, and I do not know if it is this way to find the data of who is requesting me to execute the ReverseString
End;
3
If you do a Search - Files in Files for ReverseString in your Delphi Samples\Object Pascal\DataSnap folders, it will take you to various demos which call the ReverseString method. Also if you google 'delphi "servermethods" tutorial, you'll find things like this: youtube.com/watch?v=C8iqCk4O6TgMartynA
I have tried to do a similar thing and failed. "Connection level" info (servercontainerunit) is not available in the "application level" (servermethodsunit).nolaspeaker

3 Answers

2
votes

Server side session management is a solution: an advanced feature of DataSnap. When a client connects to a DataSnap server, a session is created. This session is represented with a TDSSession instance.

In a session object you put for example ip-address. In server method you can read information from session object for specific client connection.

http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Server_Side_Session_Management

1
votes

Regards,

solution:

Delphi XE5 Rest Datasnap Server. Getting Client IP Address

var
  Session: TDSSession;
  Protocol, IpAddress, AppName: string;
begin
  Session := TDSSessionManager.GetThreadSession;
  Protocol := Session.GetData('CommunicationProtocol');
  IpAddress := Session.GetData('RemoteIP');
  AppName := Session.GetData('RemoteAppName');
end;
0
votes

A very dirty solution is to create thread global variables on your ServerContainer

threadvar
  IpAddress: string;   
  ClientPort: integer;
  Protocol: string;
  AppName: string;

So you can now use these variables and you will see an independent set of values per thread/connection.

The problem of threadvar variables is that there are not emptied when your connection finishes, potentially leading to memory leaks.

So to avoid those leaks you will neeed to clear them manually when your TMethods datamodule is destroyed.

procedure TMyMethods.DataModuleDestroy(Sender: TObject);
begin
  if DatabaseCn.Connected then DatabaseCn.Close;
  IpAddress := '';
  ClientPort := 0;
  Protocol := '';
  AppName := '';
end;

I'm certain that they are far more elegant solutions, but you could use this alternative if no one else provides a better option.