Delphi - DataSnap - Rest - TServerMethods1

3

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

In the ServerMethods unit, which Delphi itself creates, has the function ReverseString , but well, how do I know who sent it?

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

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

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

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 can not find how there in%% of% 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 get information from other concurrent connections.

In the ServerMethods.ReverseString method, I tried as follows:

var
    ADSServerClass : TDSServerClass;
begin
  ADSServerClass := TDSServerClass(GetOwner);
  TDSServer(ADSServerClass.Server).???
  // consegui chegar no server, mas não encontro, e não sei se é desta forma para localizar os dados de quem está me solicitando a execução do comando ReverseString 
end;
    
asked by anonymous 07.06.2017 / 16:39

1 answer

1

You only need a link between DSServer1Connect and ServerMethods classes. The idea here is to store the information in an array for example and retrieve it later from within ServerMethods .

First of all declare a class in unit ServerConteiner :

type
    TConexao = class
        IP: String;
        ClientPort: String;
        Protocol: String;
        AppName: String;
    end;

After that, within the% w / w sector% w / w we will create a variable to store these connections, in this case it will be a public :

public
    ConnectionList: TDictionary<Integer, TConexao>;

Now we have a variable with public reach, able to store the information of all the necessary connections. We need to create it in event ServerContainer of TDictionary :

procedure TServerContainer1.DataModuleCreate(Sender: TObject);
begin
    ConnectionList := TDictionary<Integer, TConexao>.Create;
end;

With this set up, let's have DataModuleCreate use this variable:

procedure TServerContainer1.DSServer1Connect(
  DSConnectEventObject: TDSConnectEventObject);
var
    conexao: TConexao;
begin
    if ConnectionList.ContainsKey(TThread.CurrentThread.ThreadID) then
    begin
        ConnectionList[TThread.CurrentThread.ThreadID].IP := DSConnectEventObject.ChannelInfo.ClientInfo.IpAddress;
        ConnectionList[TThread.CurrentThread.ThreadID].ClientPort := DSConnectEventObject.ChannelInfo.ClientInfo.ClientPort;
        ConnectionList[TThread.CurrentThread.ThreadID].Protocol := DSConnectEventObject.ChannelInfo.ClientInfo.Protocol;
        ConnectionList[TThread.CurrentThread.ThreadID].AppName := DSConnectEventObject.ChannelInfo.ClientInfo.AppName;
    end
    else
    begin
        conexao := TConexao.Create;
        conexao.IP := DSConnectEventObject.ChannelInfo.ClientInfo.IpAddress;
        conexao.ClientPort := DSConnectEventObject.ChannelInfo.ClientInfo.ClientPort;
        conexao.Protocol := DSConnectEventObject.ChannelInfo.ClientInfo.Protocol;
        conexao.AppName := DSConnectEventObject.ChannelInfo.ClientInfo.AppName;
        ConnectionList.Add(TThread.CurrentThread.ThreadID, conexao);
    end;
end;

We store the values within the ServerContainer , and notice, before creating a new record we see if it already exists through the global location variable, which is the key for this procedure TServerContainer1.DSServer1Connect dictionary.

It would also be interesting to disconnect this record so that it does not get weighed in memory, so the TDictionary event would be:

procedure TServerContainer1.DSServerDisconnect(DSConnectEventObject: TDSConnectEventObject);
begin
    ConnectionList[TThread.CurrentThread.ThreadID].Free;
    ConnectionList.Remove(TThread.CurrentThread.ThreadID);
end;

So when we disconnect, we release the instantiated object TThread.CurrentThread.ThreadID from memory through the TServerContainer1.DSServerDisconnect method and then remove that space from our dictionary. We could release the dictionary variable completely from memory in event TConexao of Free :

procedure TServerContainer1.DataModuleDestroy(Sender: TObject);
begin
    ConnectionList.Clear;
    ConnectionList.Destroy;
end;

Now finally to access the data of your unit DataModuleDestroy simply add in the uses a unit ServerContainer1 , and access the dictionary that is public, let's see:

uses
    {unit já existentes...}, ServerConteiner;

{... declarações da unit ...}

function TServerMethods.ReverseString(Value: string): string;
begin
    // Acessando a seguir a informação para usar da forma que preferir.
    ServerContainer1.ConnectionList.[TThread.CurrentThread.ThreadID].IP;

    Result := System.StrUtils.ReverseString(Value);
end;

It would be basically this, in that way you create a way of passing information globally on your application server.

    
09.06.2017 / 17:53