DataSnap i zwracanie wartości przez funkcję.

0

Napotkałem się na pewien problem. Prosta aplikacja klient-serwer. Poniżej przedstawiam kod:

KOD SERWERA

{ Zwraca liste użytkowników }
function TServerMethods.GetListUsers: TStringList;
var
  X: Integer;
  MyData: TMyQuery;
begin
  Result := TStringList.Create;
  MyData := TMyQuery.Create(nil);
  try
    MyData.Connection := FServer.MyConnection;
    MyData.SQL.Text := ('SELECT ' + raf_login + ' FROM ' + Key_RafloUser);
    MyData.Active := True;
    MyData.First;
    while not MyData.Eof do
    begin
      Result.Add(MyData.FieldByName(raf_login).AsString);
      MyData.Next;
    end;
  finally
    MyData.Free;
  end;
end;

KOD KLIENTA

procedure TForm4.Button1Click(Sender: TObject);
var
  Temp: TServerMethodsClient;
begin
  if not DataSnapConnection.Connected then
    DataSnapConnection.Open;
  Temp := TServerMethodsClient.Create(DataSnapConnection.DBXConnection);
  try
    ComboBox1.Items := Temp.GetListUsers;
  finally
    Temp.Free;
    DataSnapConnection.Close;
  end;
end;

Opis problemu:

Klient łączy się z serwerem i otrzymuje listę użytkowników. Jednakże po kilku wywołaniach procedury klienta dostaję AV lub błąd przy zamykaniu aplikacji klienta "Runtime error 216 at 00409EB8".

Natomiast aplikacja serwera zamyka się prawidłowo a FastMM4 nie wykrywa żadnych wycieków.

Próbowałem przerobić tak procedurę aby zwracać wartość przez referencję tzn.

procedure TServerMethods.GetListUsers(var ListUser:TStringList);

Jednakże to generowało mi jeszcze większe błędy.

Co robię źle, że dostaje AV?

0

Jeżeli zwracam dane poprzez TDataSet zamiast TStringList to wszystko działa poprawnie używam komponentu TClientDataSet. Czy czasami nie jest tak że złożone dane takie jak np tablice serwer musi przesyłać po przez TClientDataSet? Zastanawiam się jeszcze w jaki sposób przesyłać całe pliki ...

Kod Serwera

{ Zwraca liste użytkowników }
function TServerMethods.GetListUsers: TDataSet;
var
  MyData: TMyQuery;
  ClientDataSet1 : TClientDataSet;
begin
  ClientDataSet1 := TClientDataSet.Create(nil);
  MyData := TMyQuery.Create(nil);
  ClientDataSet1.Close;
  ClientDataSet1.FieldDefs.Clear;
  ClientDataSet1.FieldDefs.Add('field1',ftString,20);
  ClientDataSet1.CreateDataSet;
  try
    MyData.Connection := FServer.MyConnection;
    MyData.SQL.Text := ('SELECT ' + raf_login + ' FROM ' + Key_RafloUser);
    MyData.Active := True;
    MyData.First;
    while not MyData.Eof do
    begin
      ClientDataSet1.AppendRecord([MyData.FieldByName(raf_login).AsString]);
      MyData.Next;
    end;
    result := ClientDataSet1;
  finally
    //ClientDataSet1.Free;
    MyData.Free;
  end;
end;

Kod Klienta

procedure TForm4.Button1Click(Sender: TObject);
var
  link: TServerMethodsClient;
  DS: TdataSet;
  X : Integer;
begin
  if not DataSnapConnection.Connected then
    DataSnapConnection.Open;

  Link := TServerMethodsClient.Create(DataSnapConnection.DBXConnection);
  try
    DS := Link.GetListUsers;
    DS.First;
    Combobox1.Clear;
    while not DS.Eof do begin
      combobox1.Items.Add(DS.FieldByName('field1').AsString);
      DS.Next;
    end;
  finally
    Link.Free;
    DataSnapConnection.Close;
  end;
end;

WAŻNE Dlaczego NIE MA wycieków w serwerze skoro tworze dynamicznie obiekt

ClientDataSet1 := TClientDataSet.Create(nil);

i go nie zwalniam? Jeśli go zwolnię w bloku finally to funkcja przestaje działać. Czy może mi to ktoś wytłumaczyć?

0

być może w momencie zamknięcia połączenia przez klienta serwer automatycznie zwalnia dataset będący rezultatem funkcji . tego nie wiem ale tak można by się domyślać na podstawie Twoich obserwacji.
w moich aplikacjach korzystam z Tclientdataset'ów zdefiniowanych w klasie (mam na myśli tylko te, które zwracają rezultaty przez datasnapa) , nigdy nie tworzę ich dynamicznie więc zamknięcie połączenia zwalnia cały zdalny moduł danych łącznie z datasetami

1 użytkowników online, w tym zalogowanych: 0, gości: 1