Delphi datasnap отправляет изображение с сервера на сервер (для хранения в базе данных)

Я искал высоко и низко рабочее решение для отправки изображения (например, tpngimage) на сервер, используя метод datasnap, но я не могу заставить его работать.

Когда я загружаю изображение и сохраняю его в потоке памяти, я могу прочитать изображение обратно из потока - локально в клиенте, что не является сюрпризом. Но когда вызывается метод сервера, поток равен nil и ничего не содержит, остальные параметры в порядке (простой тип данных и объект).

Я что-то упустил здесь очевидное? У меня сложилось впечатление, что TStream является допустимым типом данных для методов сбора данных, но, возможно, я ошибаюсь?

На стороне клиента это выглядит так.

function TPerson.Update: Boolean;
var
  AStream : TMemoryStream;
  APicture : TPngImage;
  ASize : Integer;
begin
  if (FId > 0) then // if Id below zero we have a problem
  begin

    ClientModule1.ServerMethods1Client.UpdatePerson(Self);
    APicture := TPngImage.Create;
    AStream := TMemoryStream.Create;
    try
      // Temp just use a file
      AStream.LoadFromFile('.\images\075.png');
      ASize := AStream.Size;
      AStream.Position := 0; // wind back if needed

      // just for testing, we can read back the image from the stream
      APicture.LoadFromStream(AStream);

      ClientModule1.ServerMethods1Client.UpdatePersonPicture(self, ASize, AStream);

    finally
      FreeAndNil(AStream);
      FreeAndNil(APicture);
    end;

  end;
  FModified := False;
end;

И метод прокси выглядит так

procedure TServerMethods1Client.UpdatePersonPicture(APerson: TPerson; ASize: Integer; APictureStream: TMemoryStream);
begin
  if FUpdatePersonPictureCommand = nil then
  begin
    FUpdatePersonPictureCommand := FDBXConnection.CreateCommand;
    FUpdatePersonPictureCommand.CommandType := TDBXCommandTypes.DSServerMethod;
    FUpdatePersonPictureCommand.Text := 'TServerMethods1.UpdatePersonPicture';
    FUpdatePersonPictureCommand.Prepare;
  end;
  if not Assigned(APerson) then
    FUpdatePersonPictureCommand.Parameters[0].Value.SetNull
  else
  begin
    FMarshal := TDBXClientCommand(FUpdatePersonPictureCommand.Parameters[0].ConnectionHandler).GetJSONMarshaler;
    try
      FUpdatePersonPictureCommand.Parameters[0].Value.SetJSONValue(FMarshal.Marshal(APerson), True);
      if FInstanceOwner then
        APerson.Free
    finally
      FreeAndNil(FMarshal)
    end
    end;
  FUpdatePersonPictureCommand.Parameters[1].Value.SetInt32(ASize);
  FUpdatePersonPictureCommand.Parameters[2].Value.SetStream(APictureStream, FInstanceOwner);
  FUpdatePersonPictureCommand.ExecuteUpdate;
end;

Метод Server выглядит следующим образом - он терпит неудачу из-за того, что APictureStream равен нулю.

procedure TServerMethods1.UpdatePersonPicture(APerson: TPerson; ASize: integer;
  APictureStream: TMemoryStream);
var
  APicture : TPngImage;
begin
  fdqPersons.Close;
  fdqPersons.SQL.Clear;
  fdqPersons.Connection.StartTransaction;
  try
    fdqPersons.SQL.Add('update Persons set Picture=:Picture ');
    fdqPersons.SQL.Add('where Id=:Id');
    fdqPersons.ParamByName('Id').Value := APerson.Id;

    APicture := TPngImage.Create;
    try
       // APicture for testing - but APictureStream is nil!
       APicture.LoadFromStream(APictureStream);
       fdqPersons.ParamByName('Picture').Assign(APicture);
       fdqPersons.ExecSQL;
    finally
      FreeAndNil(APicture);
    end;
    fdqPersons.Close;
    fdqPersons.Connection.Commit;
    LogEvent(format('Person picture updated ID: %d',[APerson.id]));
  except
    on e:exception do
    begin
      fdqPersons.Connection.Rollback;
      LogEvent(format('Error updating person picture %s',[e.Message]));
      raise;
    end;
  end;
end;

1 ответ

Решение

Когда вы звоните APicture.LoadFromStream(AStream); позиция потока идет до конца, и, следовательно, при передаче его в ClientModule1 у него нет данных для чтения. Либо избавьтесь от ненужной части, где вы записываете поток в TPngImage или сбросьте позицию потока обратно в 0 сразу после этой части.

Другие вопросы по тегам