Mega Search
23.2 Million


Sign Up

Make a donation  
Recover from disgraceful Datasnap Disconnection  
News Group: embarcadero.public.delphi.database.multi-tier

I've been searching through this and all other forums for a complete example of how to make a data snap server close down any (local) sessions that have been orphaned by remote clients disconnecting abnormally (due to system crash or network issues).  While not finding a single complete example, I've put something together from various sources that looks like it works and have posted it below.

I'd be interested to hear if anyone's got any comments or improvements.  This example is using the the TCP Transport only which I've set to have the "KeepAliveEnablement" set to kaEnabled so that the disconnect event is triggered.

Regards

Steve

{code}
unit RobustServerContainerUnit1;

interface

uses System.SysUtils, System.Classes,
  Datasnap.DSTCPServerTransport,
  Datasnap.DSServer,
  Datasnap.DSCommonServer,
  Datasnap.DSAuth,
  IPPeerServer,
  System.Generics.Collections, IdBaseComponent, IdComponent, IdTCPConnection;


type
  TServerContainer1 = class(TDataModule)

    DSServer1: TDSServer;
    DSTCPServerTransport1: TDSTCPServerTransport;
    DSServerClass1: TDSServerClass;
    procedure DSServerClass1GetClass(DSServerClass: TDSServerClass;
      var PersistentClass: TPersistentClass);
    procedure DSTCPServerTransport1Connect(Event: TDSTCPConnectEventObject);
    procedure DSTCPServerTransport1Disconnect
      (Event: TDSTCPDisconnectEventObject);
    procedure DataModuleCreate(Sender: TObject);
    procedure DataModuleDestroy(Sender: TObject);
  private
    { Private declarations }
    FConnections: TObjectDictionary;
  public
  end;

var
  ServerContainer1: TServerContainer1;

implementation

uses Winapi.Windows, ServerMethodsUnit1;

{$R *.dfm}

procedure TServerContainer1.DataModuleCreate(Sender: TObject);
begin
  FConnections := TObjectDictionary.create;
end;

procedure TServerContainer1.DataModuleDestroy(Sender: TObject);
begin
  FConnections.free;
end;

procedure TServerContainer1.DSServerClass1GetClass(DSServerClass
  : TDSServerClass; var PersistentClass: TPersistentClass);
begin
  PersistentClass := ServerMethodsUnit1.TServerMethods1;
end;

procedure TServerContainer1.DSTCPServerTransport1Connect
  (Event: TDSTCPConnectEventObject);
begin
  System.TMonitor.Enter(FConnections);
  try
    FConnections.Add(TIdTCPConnection(Event.Connection), Event.Channel);
    // Event.Channel has a SessionId property
  finally
    System.TMonitor.Exit(FConnections);
  end;

end;

procedure TServerContainer1.DSTCPServerTransport1Disconnect
  (Event: TDSTCPDisconnectEventObject);
var
  tmpChannel: TDSTCPChannel;
begin
  if FConnections.TryGetValue(TIdTCPConnection(Event.Connection), tmpChannel) then
  begin
      tmpChannel.Close;
  end;
  System.TMonitor.Enter(FConnections);
  try
    FConnections.Remove(TIdTCPConnection(Event.Connection));
  finally
    System.TMonitor.Exit(FConnections);
  end;
end;

end.
{code}

Vote for best question.
Score: 0  # Vote:  0
Date Posted: 10-Apr-2014, at 5:45 AM EST
From: Stephen Corbett