Delphi - Datasnap - Rest - Tservermethods1

Asked

Viewed 1,028 times

4

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

Back at the Unit ServerMethods, that Delphi itself creates, has the function ReverseString, but well, how do I know who sent it?

I’d like to keep one log information from customers who called this method.

I know I could pass as a parameter, but it would be up to the client to give me this information, which I don’t want, let’s say the method would be public and various clients would fire this information. I can easily lose this control if I don’t get the information directly by the server control.

I found on the web, that in Unit ServerConteiner, has an object DSServer, this object has an event called OnConnect, for it I can take 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’t seem to find it like ServerMethods.ReverseString I can take this data.

I believe the processing is in thread on the server, so I cannot pass this value as global, as it can take information from other simultaneous connections.

In the method ReverseString, I tried it this way:

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;
  • Solution at: http://blog.atlabs.com.br/2017/06/delphi-pegando-o-ip-cliente-em-um.html

1 answer

3

You just need a connection between the DSServer1Connect with the classes ServerMethods. The idea here is to store the information in an array for example and retrieve it later from within the 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 sector public of ServerContainer we will create a variable to store these connections, in case it will be a TDictionary:

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 the event DataModuleCreate of ServerContainer:

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

With that prepared, we will make the procedure TServerContainer1.DSServer1Connect 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 TDictionary, and notice, before creating a new record we see if it already exists through the global location variable, which is the key to that dictionary TThread.CurrentThread.ThreadID.

It would be interesting also in disconnecting remove this record to not keep weighing in memory, so the event TServerContainer1.DSServerDisconnect would be:

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

So when disconnecting we release the instantiated object TConexao memory through the method Free and then remove that space from our dictionary. We could release the dictionary variable completely from memory in the event DataModuleDestroy of ServerContainer1:

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

Now finally to access your Unit data ServerMethods just add no uses to Unit ServerConteiner, 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;

That’s basically it, that way you create a global information gateway on your application server.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.