Watch, Follow, &
Connect with Us
Public Report
Report From: Delphi-BCB/Database/DataSnap    [ Add a report in this area ]  
Report #:  78698   Status: Open
Encounter "Invalid command handle" when consume more than one server method at runtime for in-process application
Project:  Delphi Build #:  14.0.3513.24210
Version:    14.0 Submitted By:   Chee Yang Chau
Report Type:  Crash / Data loss / Total failure Date Reported:  10/15/2009 9:57:57 PM
Severity:    Critical / Show Stopper Last Updated: 4/9/2012 12:47:06 AM
Platform:    All platforms Internal Tracking #:   27106
Resolution: None (Resolution Comments) Resolved in Build: : None
Duplicate of:  None
Voting and Rating
Overall Rating: No Ratings Yet
0.00 out of 5
Total Votes: 13
Description
I define a class with 2 server methods:

  TMyServerMethod = class(TPersistent)
  public
    function EchoString(Value: string): string;
    function Sum(const a, b: integer): integer;
  end;

I generate a proxy client class for the server methods.

I then invoke the proxy client as this:

var o: TDataModule1;
    Q: TSQLConnection;
    c: TMyServerMethodClient;
begin
  o := TDataModule1.Create(Self);
  Q := TSQLConnection.Create(Self);
  try
    Q.DriverName := 'DSServer1';
    Q.LoginPrompt := False;
    Q.Open;

    c := TMyServerMethodClient.Create(Q.DBXConnection);
    try
      ShowMessage(c.EchoString('Hello'));
      ShowMessage(IntToStr(c.Sum(100, 200)));
    finally
      c.Free;
    end;
  finally
    o.Free;
    Q.Free;
  end;
end;

It will prompt "Invlaid command handle" after invoke second server method.

I think the problem occurs in class TDSServerCommand.  There are 3 methods in the class invoke

  FServerCon.PrepareMessage.CommandHandle

These methods are
  1. procedure TDSServerCommand.Execute;
  2. procedure TDSServerCommand.DerivedClose;
  3. function TDSServerCommand.DerivedGetNextReader: TDBXReader;

FServerCon is an instance shared by all TDSServerCommand instances in a container:

constructor TDSServerCommand.Create(const Context: TDBXContext; const AServerCon: TDSServerConnection; const AConHandler: TDSServerConnectionHandler);
begin
  inherited Create(Context);
  FConHandler := AConHandler;
  FServerCon := AServerCon;
end;

"FServerCon.PrepareMessage.CommandHandle" is prepared in method

  procedure TDSServerCommand.DerivedPrepare;

If we create more than one instance of TDSServerCommand for same Server Connection and invoke these commands in arbitrary orders, it will definitely failed at some point.

The reason is simple, "FServerCon.PrepareMessage.CommandHandle" always return the latest command handle ID.

For example, in the sample project fro attachment, there are 2 methods available: EchoString() and Sum().

If we instantiate EchoString() first followed by Sum(), both commands will have CommandHandle of 0 and 1 respectively.

If we invoke the commands in this order:

  1. EchoString  (use CommandHandle = 0)
  2. Sum  (use CommandHandle = 1)
  3. EchoString (use CommandHandle = 1)

Please note that the 3rd invoke will fail as the CommandHandle belongs to Sum() method.

Likewise, when the command is closed (via procedure TDSServerCommand.DerivedClose), it will close the CommandHandle = 1 twice in the attached project.
Steps to Reproduce:
1. Extract the attachment
2. Compile and run in Delph 2010
3. Click Button1
4. Prompt "Invalid Command Handle"
Workarounds
Refer to http://chee-yang.blogspot.com/2009/10/datasnap-in-process-server-method.html
Attachment
78698.zip
Comments

Michael Leaver at 10/1/2012 2:01:14 AM -
Still happens in XE3.

Chee Yang Chau at 5/14/2013 2:18:34 AM -
Still happens in XE4

Chee Yang Chau at 5/20/2014 8:46:30 PM -
Still happens in XE5 and XE6

Chee Yang Chau at 9/17/2015 1:52:01 AM -
Still happens in XE7, XE8 and RAD Studio 10 Seattle

Server Response from: ETNACODE01