title: delphi datasnap memory leak
body: <p>I am prototyping a datasnap client and server application. I want to stream a file from the server to the client.</p>
  
  <p>This is working, but every file that i stream stays in memory at the server. It is never released, not even when i close the connection / client.</p>
  
  <p>I tried using: <code>GetInvocationMetaData.CloseSession := True;</code>
  in the method call on the server, but then i don't get a file, it is 0 Kb.</p>
  
  <p>What am I doing wrong?</p>
  
  <p>Serverside code: (excuse me for the naming)
  Lifecycle is invocation</p>
  
  <pre><code>unit ServerMethodsUnitNKDataSnap;
  
  interface
  
  uses System.SysUtils, System.Classes, Datasnap.DSServer, Datasnap.DSAuth,
    Data.DB, IBCustomDataSet, IBQuery, IBDatabase, Datasnap.Provider, DataSnap.DSSession, Data.DBXPlatform;
  
  type
    TServerMethods1 = class(TDSServerModule)
    private
  //    FStream:TStream;
    public
      { Public declarations }
      function EchoString(Value: string): string;
      function ReverseString(Value: string): string;
      function DownloadFile(sFile:String): TStream;
      function BestaatFile(sFile:String):Boolean;
      procedure FreeStream;
    end;
  
  implementation
  
  {$R *.dfm}
  
  uses System.StrUtils;
  
  function TServerMethods1.EchoString(Value: string): string;
  begin
    Result := Value;
  end;
  
  procedure TServerMethods1.FreeStream;
  begin
  //  FreeAndNil(FStream);
    GetInvocationMetaData.CloseSession := True;
  end;
  
  function TServerMethods1.ReverseString(Value: string): string;
  begin
    Result := System.StrUtils.ReverseString(Value);
    GetInvocationMetaData.CloseSession := True;
  end;
  
  function TServerMethods1.DownloadFile(sFile:String): TStream;
  begin
  {
    if Assigned(FStream) then
      FreeAndNil(FStream);
    FStream := TFileStream.Create(sFile, fmOpenRead or fmShareDenyNone);
  
    Result := FStream;
    TFileStream(Result).Seek(0, TSeekOrigin.soBeginning);
  }
    result := TFileStream.Create(sFile, fmOpenRead or fmShareDenyNone);
    TFileStream(Result).Seek(0, TSeekOrigin.soBeginning);
  //  GetInvocationMetaData.CloseSession := True;
  end;
  
  function TServerMethods1.BestaatFile(sFile: string):Boolean;
  begin
    Result := FileExists(sFile);
    GetInvocationMetaData.CloseSession := True;
  end;
  
  end.
  </code></pre>
  
  <p>dfm</p>
  
  <pre><code>object ServerContainer2: TServerContainer2
    OldCreateOrder = False
    Height = 271
    Width = 415
    object DSServer1: TDSServer
      Left = 96
      Top = 11
    end
    object DSHTTPService1: TDSHTTPService
      HttpPort = 7070
      Server = DSServer1
      Filters = &lt;&gt;
      Left = 96
      Top = 135
    end
    object DSServerClass1: TDSServerClass
      OnGetClass = DSServerClass1GetClass
      Server = DSServer1
      LifeCycle = 'Invocation'
      Left = 200
      Top = 11
    end
  end
  </code></pre>
  
  <p>client side code
  generated source</p>
  
  <pre><code>//
  // Created by the DataSnap proxy generator.
  // 2-2-2015 14:27:21
  //
  
  unit ClientClassesUnit1;
  
  interface
  
  uses Datasnap.DSProxyRest, Datasnap.DSClientRest, Data.DBXCommon, Data.DBXClient, Data.DBXDataSnap, Data.DBXJSON, Datasnap.DSProxy, System.Classes, System.SysUtils, Data.DB, Data.SqlExpr, Data.DBXDBReaders, Data.DBXCDSReaders, Data.DBXJSONReflect;
  
  type
    TServerMethods1Client = class(TDSAdminRestClient)
    private
      FEchoStringCommand: TDSRestCommand;
      FReverseStringCommand: TDSRestCommand;
      FDownloadFileCommand: TDSRestCommand;
      FDownloadFileCommand_Cache: TDSRestCommand;
      FBestaatFileCommand: TDSRestCommand;
      FFreeStreamCommand: TDSRestCommand;
    public
      constructor Create(ARestConnection: TDSRestConnection); overload;
      constructor Create(ARestConnection: TDSRestConnection; AInstanceOwner: Boolean); overload;
      destructor Destroy; override;
      function EchoString(Value: string; const ARequestFilter: string = ''): string;
      function ReverseString(Value: string; const ARequestFilter: string = ''): string;
      function DownloadFile(sFile: string; const ARequestFilter: string = ''): TStream;
      function DownloadFile_Cache(sFile: string; const ARequestFilter: string = ''): IDSRestCachedStream;
      function BestaatFile(sFile: string; const ARequestFilter: string = ''): Boolean;
      procedure FreeStream;
    end;
  
  const
    TServerMethods1_EchoString: array [0..1] of TDSRestParameterMetaData =
    (
      (Name: 'Value'; Direction: 1; DBXType: 26; TypeName: 'string'),
      (Name: ''; Direction: 4; DBXType: 26; TypeName: 'string')
    );
  
    TServerMethods1_ReverseString: array [0..1] of TDSRestParameterMetaData =
    (
      (Name: 'Value'; Direction: 1; DBXType: 26; TypeName: 'string'),
      (Name: ''; Direction: 4; DBXType: 26; TypeName: 'string')
    );
  
    TServerMethods1_DownloadFile: array [0..1] of TDSRestParameterMetaData =
    (
      (Name: 'sFile'; Direction: 1; DBXType: 26; TypeName: 'string'),
      (Name: ''; Direction: 4; DBXType: 33; TypeName: 'TStream')
    );
  
    TServerMethods1_DownloadFile_Cache: array [0..1] of TDSRestParameterMetaData =
    (
      (Name: 'sFile'; Direction: 1; DBXType: 26; TypeName: 'string'),
      (Name: ''; Direction: 4; DBXType: 26; TypeName: 'String')
    );
  
    TServerMethods1_BestaatFile: array [0..1] of TDSRestParameterMetaData =
    (
      (Name: 'sFile'; Direction: 1; DBXType: 26; TypeName: 'string'),
      (Name: ''; Direction: 4; DBXType: 4; TypeName: 'Boolean')
    );
  
  implementation
  
  function TServerMethods1Client.EchoString(Value: string; const ARequestFilter: string): string;
  begin
    if FEchoStringCommand = nil then
    begin
      FEchoStringCommand := FConnection.CreateCommand;
      FEchoStringCommand.RequestType := 'GET';
      FEchoStringCommand.Text := 'TServerMethods1.EchoString';
      FEchoStringCommand.Prepare(TServerMethods1_EchoString);
    end;
    FEchoStringCommand.Parameters[0].Value.SetWideString(Value);
    FEchoStringCommand.Execute(ARequestFilter);
    Result := FEchoStringCommand.Parameters[1].Value.GetWideString;
  end;
  
  function TServerMethods1Client.ReverseString(Value: string; const ARequestFilter: string): string;
  begin
    if FReverseStringCommand = nil then
    begin
      FReverseStringCommand := FConnection.CreateCommand;
      FReverseStringCommand.RequestType := 'GET';
      FReverseStringCommand.Text := 'TServerMethods1.ReverseString';
      FReverseStringCommand.Prepare(TServerMethods1_ReverseString);
    end;
    FReverseStringCommand.Parameters[0].Value.SetWideString(Value);
    FReverseStringCommand.Execute(ARequestFilter);
    Result := FReverseStringCommand.Parameters[1].Value.GetWideString;
  end;
  
  function TServerMethods1Client.DownloadFile(sFile: string; const ARequestFilter: string): TStream;
  begin
    if FDownloadFileCommand = nil then
    begin
      FDownloadFileCommand := FConnection.CreateCommand;
      FDownloadFileCommand.RequestType := 'GET';
      FDownloadFileCommand.Text := 'TServerMethods1.DownloadFile';
      FDownloadFileCommand.Prepare(TServerMethods1_DownloadFile);
    end;
    FDownloadFileCommand.Parameters[0].Value.SetWideString(sFile);
    FDownloadFileCommand.Execute(ARequestFilter);
    Result := FDownloadFileCommand.Parameters[1].Value.GetStream(FInstanceOwner);
  end;
  
  function TServerMethods1Client.DownloadFile_Cache(sFile: string; const ARequestFilter: string): IDSRestCachedStream;
  begin
    if FDownloadFileCommand_Cache = nil then
    begin
      FDownloadFileCommand_Cache := FConnection.CreateCommand;
      FDownloadFileCommand_Cache.RequestType := 'GET';
      FDownloadFileCommand_Cache.Text := 'TServerMethods1.DownloadFile';
      FDownloadFileCommand_Cache.Prepare(TServerMethods1_DownloadFile_Cache);
    end;
    FDownloadFileCommand_Cache.Parameters[0].Value.SetWideString(sFile);
    FDownloadFileCommand_Cache.ExecuteCache(ARequestFilter);
    Result := TDSRestCachedStream.Create(FDownloadFileCommand_Cache.Parameters[1].Value.GetString);
  end;
  
  function TServerMethods1Client.BestaatFile(sFile: string; const ARequestFilter: string): Boolean;
  begin
    if FBestaatFileCommand = nil then
    begin
      FBestaatFileCommand := FConnection.CreateCommand;
      FBestaatFileCommand.RequestType := 'GET';
      FBestaatFileCommand.Text := 'TServerMethods1.BestaatFile';
      FBestaatFileCommand.Prepare(TServerMethods1_BestaatFile);
    end;
    FBestaatFileCommand.Parameters[0].Value.SetWideString(sFile);
    FBestaatFileCommand.Execute(ARequestFilter);
    Result := FBestaatFileCommand.Parameters[1].Value.GetBoolean;
  end;
  
  procedure TServerMethods1Client.FreeStream;
  begin
    if FFreeStreamCommand = nil then
    begin
      FFreeStreamCommand := FConnection.CreateCommand;
      FFreeStreamCommand.RequestType := 'GET';
      FFreeStreamCommand.Text := 'TServerMethods1.FreeStream';
    end;
    FFreeStreamCommand.Execute;
  end;
  
  constructor TServerMethods1Client.Create(ARestConnection: TDSRestConnection);
  begin
    inherited Create(ARestConnection);
  end;
  
  constructor TServerMethods1Client.Create(ARestConnection: TDSRestConnection; AInstanceOwner: Boolean);
  begin
    inherited Create(ARestConnection, AInstanceOwner);
  end;
  
  destructor TServerMethods1Client.Destroy;
  begin
    FEchoStringCommand.DisposeOf;
    FReverseStringCommand.DisposeOf;
    FDownloadFileCommand.DisposeOf;
    FDownloadFileCommand_Cache.DisposeOf;
    FBestaatFileCommand.DisposeOf;
    FFreeStreamCommand.DisposeOf;
    inherited;
  end;
  
  end.
  </code></pre>
  
  <p>Own source</p>
  
  <pre><code>unit Unit1;
  
  interface
  
  uses
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
    Vcl.Grids, Vcl.DBGrids, IPPeerClient, Datasnap.DSClientRest;
  
  type
    TForm1 = class(TForm)
      Button1: TButton;
      Edit1: TEdit;
      Label4: TLabel;
      Button5: TButton;
      Edit5: TEdit;
      Label5: TLabel;
      Edit6: TEdit;
      Label6: TLabel;
      DSRestConnection1: TDSRestConnection;
      procedure Button1Click(Sender: TObject);
      procedure Button5Click(Sender: TObject);
    private
      procedure DownloadFile(sSourceFile,sTargetFile:string);
    public
      { Public declarations }
    end;
  
  var
    Form1: TForm1;
  
  implementation
  
  uses ClientClassesUnit1;
  
  {$R *.dfm}
  
  procedure TForm1.Button1Click(Sender: TObject);
  var oServerMethodsClient:TServerMethods1Client;
  begin
    oServerMethodsClient := nil;
    try
      try
        oServerMethodsClient := TServerMethods1Client.Create(DSRestConnection1, True);
        ShowMessage(oServerMethodsClient.EchoString(edit1.Text));
        ShowMessage(oServerMethodsClient.ReverseString(edit1.Text));
      except
        on E: Exception do
        begin
          showmessage('Oeps echo: ' + E.Message);
        end;
      end;
    finally
      FreeAndNil(oServerMethodsClient);
    end;
  end;
  
  procedure TForm1.Button5Click(Sender: TObject);
  begin
    DownloadFile(edit5.Text, edit6.Text);
  end;
  
  procedure TForm1.DownloadFile(sSourceFile,sTargetFile:String);
  var
      RetStream: TStream;
      fs:TFileStream;
      oServerMethodsClient:TServerMethods1Client;
  begin
    oServerMethodsClient := nil;
    RetStream := nil;
  
    try
      try
        oServerMethodsClient := TServerMethods1Client.Create(DSRestConnection1, True);
        RetStream := oServerMethodsClient.DownloadFile(sSourceFile);
  //      oServerMethodsClient.FreeStream;
        fs := TFileStream.Create(sTargetFile, fmCreate);
        try
          if RetStream.Size &gt; 0 then
          begin
            RetStream.Position:=0;
            fs.CopyFrom(RetStream, RetStream.Size);
          end;
        finally
           fs.free;
  //         retstream.Free;
        end;
  
      except
        on E: Exception do
        begin
          showmessage('Oeps download: ' + E.Message);
        end;
      end;
  
    finally
      FreeAndNil(oServerMethodsClient);
    end;
  end;
  
  end.
  </code></pre>
  
  <p>dfm source</p>
  
  <pre><code>object Form1: TForm1
    Left = 0
    Top = 0
    Caption = 'Form1'
    ClientHeight = 519
    ClientWidth = 959
    Color = clBtnFace
    Font.Charset = DEFAULT_CHARSET
    Font.Color = clWindowText
    Font.Height = -11
    Font.Name = 'Tahoma'
    Font.Style = []
    OldCreateOrder = False
    PixelsPerInch = 96
    TextHeight = 13
    object Label4: TLabel
      Left = 208
      Top = 48
      Width = 53
      Height = 13
      Caption = 'Echo string'
    end
    object Label5: TLabel
      Left = 208
      Top = 93
      Width = 22
      Height = 13
      Caption = 'van:'
    end
    object Label6: TLabel
      Left = 208
      Top = 123
      Width = 22
      Height = 13
      Caption = 'naar'
    end
    object Button1: TButton
      Left = 16
      Top = 43
      Width = 75
      Height = 25
      Caption = 'echo'
      TabOrder = 0
      OnClick = Button1Click
    end
    object Edit1: TEdit
      Left = 288
      Top = 45
      Width = 274
      Height = 21
      TabOrder = 1
      Text = 'bla'
    end
    object Button5: TButton
      Left = 16
      Top = 88
      Width = 75
      Height = 25
      Caption = 'haal 1 file'
      TabOrder = 2
      OnClick = Button5Click
    end
    object Edit5: TEdit
      Left = 288
      Top = 93
      Width = 274
      Height = 21
      TabOrder = 3
      Text = 'c:\source\temp.zip'
    end
    object Edit6: TEdit
      Left = 288
      Top = 120
      Width = 274
      Height = 21
      TabOrder = 4
      Text = 'c:\temp\temp.zip'
    end
    object DSRestConnection1: TDSRestConnection
      Host = 'localhost'
      Port = 7070
      LoginPrompt = False
      PreserveSessionID = False
      Left = 120
      Top = 16
      UniqueId = '{B4909821-9EF2-42F1-AFFF-58B320C35F75}'
    end
  end
  </code></pre>