Recover from disgraceful Datasnap Disconnection |
|
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}
|