title: DELPHI: Multithreaded client/server datasnap error
body: <p>This is my first post here - so be gentle :-)</p>
  
  <p>I want to build a client/server application that uses datasnap for data transport.
  This is a fairly simple task - and there are lots of examples to learn from.
  BUT - Having a Datasnap server (build from Delphi XE wizard) I find myself running into a problem, and I hope someone can guide me into the right direction.</p>
  
  <p>Server and Client run on same PC (that is the design for now).
  Server is running Session lifecycle.
  Server and Client shares a class (posted below)..</p>
  
  <p>The Server provides a simple method - GetServerObject which uses the GetNewObject method.
  The Server itself is a VCL application - main form is fmServer.
  OnCreate instatiates the Servers FormObject property (FormObject := TMyDataObject.Create);</p>
  
  <pre><code>function TServerMethods2.GetNewObject: TMyDataObject;
  begin
    Result := TMyDataObject.Create;
  end;
  
  function TServerMethods2.GetServerObject: TMyDataObject;
  begin
    Result := GetNewObject;
    if not Result.Assign(fmServer.FormObject) then
      raise Exception.Create('Server error : Assign failed!');
  end;
  </code></pre>
  
  <p>All this is pretty trivial - and my problem only appears if I twist my Client application into a multithreaded monster :-) (read - more than 1 thread).</p>
  
  <p>So here is the Thread code for the client.</p>
  
  <pre><code>  TDataThread = class(TThread)
    private
      DSConn: TSQLConnection;
    protected
      procedure Execute; override;
    public
      constructor Create(aConn: TSQLConnection); overload;
    end;
  
  constructor TDataThread.Create(aConn: TSQLConnection);
  begin
    inherited Create(False);
    DSConn := aConn.CloneConnection;
    FreeOnTerminate := true;
  end;
  
  procedure TDataThread.Execute;
  var
    DSMethod: TServerMethods2Client;
    aDataObject : TMyDataObject;
  begin
    NameThreadForDebugging('Data');
    { Place thread code here }
    DSMethod := nil;
    try
      while not terminated do
      begin
        sleep(10);
        if DSConn.Connected then
        begin
          try
            if DSMethod = nil then
              DSMethod := TServerMethods2Client.Create(DSConn.DBXConnection,false);
            if DSMethod &lt;&gt; nil then
              try
                aDataObject := DSMethod.GetserverObject;
              finally
                freeandnil(aDataObject);
              end;
          except
            freeandnil(DSMethod);
            DSConn.Connected := False;
          end
        end
        else
        begin
          // connect
          try
            sleep(100);
            DSConn.Open;
          except
            ;
          end;
        end;
      end;
    finally
      freeandnil(DSMethod);
      DSConn.Close;
      freeandnil(DSConn);
    end;
  </code></pre>
  
  <p>When I create more than 1 of these threads - eventually I will get an error (being "cannot instatiate ... " or some "remote dbx error ..." .. and so on.</p>
  
  <p>I simply cannot get this to work - so that I can spawn hundreds of threads/connections to a datasnap server.</p>
  
  <p>I know this question is tricky - but my hope is that someone is smarter than me :-)</p>
  
  <p>If I try the same client thread code - but accessing a more simple server method (lets say echostring from sample) then I can run it with hundreds of threads.
  Perhaps Im answering myself here - but Im too blind to realize it :-)</p>
  
  <pre><code>unit uDataObject;
  
  interface
  
  uses
    SysUtils;
  
  Type
    TMyDataObject = class(TObject)
    private
      fString: String;
      fInteger: Integer;
    public
      constructor Create; virtual;
      destructor Destroy; override;
      function Assign(aSource: TMyDataObject): boolean;
      property aString: String read fString write fString;
      property aInteger: Integer read fInteger write fInteger;
    end;
  
  implementation
  
  { TMyDataObject }
  
  function TMyDataObject.Assign(aSource: TMyDataObject): boolean;
  begin
    if aSource &lt;&gt; nil then
    begin
      try
        fString := aSource.aString;
        fInteger := aSource.aInteger;
        Result := True;
      except
        Result := false;
      end;
    end
    else
      Result := false;
  end;
  
  constructor TMyDataObject.Create;
  begin
    inherited;
    Randomize;
    fString := 'The time of creation is : ' + FormatDateTime('ddmmyyyy hh:nn:ss:zzz', Now);
    fInteger := Random(100);
  end;
  
  destructor TMyDataObject.Destroy;
  begin
    inherited;
  end;
  end.
  </code></pre>
  
  <p>All help is appreciated </p>