Delphi-PRAXiS
Seite 3 von 3     123   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi Datasnap File Upload (https://www.delphipraxis.net/164871-datasnap-file-upload.html)

Captnemo 12. Sep 2012 07:59

AW: Datasnap File Upload
 
Sorry, hat mehrfach gepostet.

Uwe Raabe 12. Sep 2012 09:18

AW: Datasnap File Upload
 
Zitat:

Zitat von Captnemo (Beitrag 1182579)
Delphi-Quellcode:
      aClient.UploadFile(aFileStream, 'Upload', ExtractFileName(JvFilenameEdit1.Text));

Zeig mal, was da in UploadFile passiert.

Uwe Raabe 12. Sep 2012 09:44

AW: Datasnap File Upload
 
Um das mal etwas näher zu erläutern: Beim Create eines Proxy kann man als zweiten Parameter angeben, ob der Proxy der InstanceOwner ist. Lässt man diesen Parameter weg, wird true angenommen. Als InstanceOwner kümmert sich der Proxy selbst um die übergebenen und erhaltenen Instanzen. Ich vermute, das ist in diesem Fall auch so. Daher meine Frage nach der Implementation von UploadFile.

Captnemo 12. Sep 2012 10:54

AW: Datasnap File Upload
 
Hier ist mein Proxy:
Delphi-Quellcode:
//
// Erzeugt vom DataSnap-Proxy-Generator.
// 11.09.2012 15:05:33
//

unit proxy;

interface

uses Data.DBXCommon, Data.DBXClient, Data.DBXDataSnap, Data.DBXJSON, Datasnap.DSProxy, System.Classes, System.SysUtils, Data.DB, Data.SqlExpr, Data.DBXDBReaders, Data.DBXJSONReflect;

type
  TServerMethods1Client = class(TDSAdminClient)
  private
    FEchoStringCommand: TDBXCommand;
    FReverseStringCommand: TDBXCommand;
    FUploadFileCommand: TDBXCommand;
  public
    constructor Create(ADBXConnection: TDBXConnection); overload;
    constructor Create(ADBXConnection: TDBXConnection; AInstanceOwner: Boolean); overload;
    destructor Destroy; override;
    function EchoString(Value: string): string;
    function ReverseString(Value: string): string;
    procedure UploadFile(str: TStream; Store: string; FileName: string);
  end;

implementation

function TServerMethods1Client.EchoString(Value: string): string;
begin
  if FEchoStringCommand = nil then
  begin
    FEchoStringCommand := FDBXConnection.CreateCommand;
    FEchoStringCommand.CommandType := TDBXCommandTypes.DSServerMethod;
    FEchoStringCommand.Text := 'TServerMethods1.EchoString';
    FEchoStringCommand.Prepare;
  end;
  FEchoStringCommand.Parameters[0].Value.SetWideString(Value);
  FEchoStringCommand.ExecuteUpdate;
  Result := FEchoStringCommand.Parameters[1].Value.GetWideString;
end;

function TServerMethods1Client.ReverseString(Value: string): string;
begin
  if FReverseStringCommand = nil then
  begin
    FReverseStringCommand := FDBXConnection.CreateCommand;
    FReverseStringCommand.CommandType := TDBXCommandTypes.DSServerMethod;
    FReverseStringCommand.Text := 'TServerMethods1.ReverseString';
    FReverseStringCommand.Prepare;
  end;
  FReverseStringCommand.Parameters[0].Value.SetWideString(Value);
  FReverseStringCommand.ExecuteUpdate;
  Result := FReverseStringCommand.Parameters[1].Value.GetWideString;
end;

procedure TServerMethods1Client.UploadFile(str: TStream; Store: string; FileName: string);
begin
  if FUploadFileCommand = nil then
  begin
    FUploadFileCommand := FDBXConnection.CreateCommand;
    FUploadFileCommand.CommandType := TDBXCommandTypes.DSServerMethod;
    FUploadFileCommand.Text := 'TServerMethods1.UploadFile';
    FUploadFileCommand.Prepare;
  end;
  FUploadFileCommand.Parameters[0].Value.SetStream(str, FInstanceOwner);
  FUploadFileCommand.Parameters[1].Value.SetWideString(Store);
  FUploadFileCommand.Parameters[2].Value.SetWideString(FileName);
  FUploadFileCommand.ExecuteUpdate;
end;


constructor TServerMethods1Client.Create(ADBXConnection: TDBXConnection);
begin
  inherited Create(ADBXConnection);
end;


constructor TServerMethods1Client.Create(ADBXConnection: TDBXConnection; AInstanceOwner: Boolean);
begin
  inherited Create(ADBXConnection, AInstanceOwner);
end;


destructor TServerMethods1Client.Destroy;
begin
  FreeAndNil(FEchoStringCommand);
  FreeAndNil(FReverseStringCommand);
  FreeAndNil(FUploadFileCommand);
  inherited;
end;

end.
und hier mein Server:
Delphi-Quellcode:
unit ServerMethodsUnit1;

interface

uses System.SysUtils, System.Classes, Datasnap.DSServer, Datasnap.DSAuth;

type
{$METHODINFO ON}
  TServerMethods1 = class(TComponent)
  private
    { Private declarations }
  public
    { Public declarations }
    function EchoString(Value: string): string;
    function ReverseString(Value: string): string;
    procedure UploadFile(str: TStream; Store, FileName: String);
  end;
{$METHODINFO OFF}

implementation


uses System.StrUtils;

procedure TServerMethods1.UploadFile(str: TStream; Store, FileName: String);
var
  aFileStream: TFileStream;
  BytesReadCount: Integer;
  Buffer: array [1 .. 16 * 1024] of Byte;
  strPfad: String;
begin
  strPfad := 'C:\' + Store;
  if not DirectoryExists(strPfad) then
  begin
    MkDir(strPfad);
  end;
  aFileStream := TFileStream.Create(strPfad + '\' + FileName, fmCreate);
  try
    repeat
      BytesReadCount := str.Read(Buffer, SizeOf(Buffer));
      aFileStream.Write(Buffer, BytesReadCount);
    until (BytesReadCount < SizeOf(Buffer));
    str.Position := 0;
  finally
    aFileStream.Free;
  end;
end;

function TServerMethods1.EchoString(Value: string): string;
begin
  Result := Value;
end;

function TServerMethods1.ReverseString(Value: string): string;
begin
  Result := System.StrUtils.ReverseString(Value);
end;
end.
Was du sagst, mit dem InstanceOwner, verstehe ich. Aber was ist dann der Unterschied zwischen den beiden Funktionen?
Delphi-Quellcode:
procedure TForm2.Button1Click(Sender: TObject);
var
  aClient: TServerMethods1Client;
begin
  aClient := TServerMethods1Client.Create(SQLCOnnection1.DBXConnection);
  Try
    Edit1.Text := aClient.ReverseString(Edit1.Text);
  Finally
    aClient.Free;
  End;
 end;

procedure TForm2.Button2Click(Sender: TObject);
var
  aClient: TServerMethods1Client;
  aFileStream: TFileStream;
 begin
  aClient := TServerMethods1Client.Create(SQLCOnnection1.DBXConnection);
  Try
    aFileStream := TFileStream.Create(JvFilenameEdit1.Text, fmOpenRead);
    try
      aClient.UploadFile(aFileStream, 'Upload', ExtractFileName(JvFilenameEdit1.Text));
    except
      ShowMessage('Übertragung fehlerhaft!');
    end;
  Finally
    aFileStream.Free;
    aClient.Free;
  End;
end;
in beiden erzeuge ich das Objekt aClient auf die gleiche Weise. Demnach müßte ja in beiden Funktion der gleiche Fehler auftreten. Tut er aber nicht.

Uwe Raabe 12. Sep 2012 12:30

AW: Datasnap File Upload
 
Zitat:

Zitat von Captnemo (Beitrag 1182596)
Delphi-Quellcode:
  FUploadFileCommand.Parameters[0].Value.SetStream(str, FInstanceOwner);

In dieser Zeile wird dem Value mitgeteilt, ob er sich um die Freigabe des übergebenen Streams kümmern soll oder nicht. Da du das einfache Create verwendest, ist FInstanceOwner implizit true. Du kannst also entweder beim Create noch ein False übergeben oder (empfohlen) das aFileStream.Free im Button2Click weglassen. Das Problem ist also nicht das aClient.Free!

Aus diesem Grund hast du auch bei ReverseString keine Probleme, da dort keine Instanzen freigegeben werden müssen.

Captnemo 12. Sep 2012 12:52

AW: Datasnap File Upload
 
Das habe ich verstanden. Vielen Dank. Mal sehen, wie weit ich jetzt komme :-D

himitsu 12. Sep 2012 13:23

AW: Datasnap File Upload
 
Datasnap gibt (standardmäßig) Streams frei, welche übertragen wurden, also wenn man die automatisch generierten Clientklassen verwendet.

Wenn du es selbst nochmal freigibst, dann knallt es natürlich.


Vertausche mal
Delphi-Quellcode:
aFileStream.Free;
und
Delphi-Quellcode:
aClient.Free;
, oder kommentiere
Delphi-Quellcode:
aFileStream.Free;
aus.

[edit]
Komisch, alles ab 13:30 war eben noch nicht sichtbar. :shock:

In einer der automatisch generierten Clientklassen baut Delphi ein Property ein, wo du dieses Freigeben deaktivieren kannst.

Uwe Raabe 12. Sep 2012 13:42

AW: Datasnap File Upload
 
Zitat:

Zitat von himitsu (Beitrag 1182626)
Vertausche mal
Delphi-Quellcode:
aFileStream.Free;
und
Delphi-Quellcode:
aClient.Free;

Jetzt nicht wirklich, oder? Die Instanz wird zwar automatisch freigegeben, aber die Variable aFileStream wird damit nicht zwangsläufig auf nil gesetzt.

himitsu 12. Sep 2012 13:51

AW: Datasnap File Upload
 
Neee nee, das war nicht zur Fehlerbehandlung ... Ich war nur mal neugierig, wie/ob sich dann die Fehlerposition verschiebt.

Ich bin eher der Meinung, daß der Stream schon direkt nach dem Übertragen freigegeben wird, womit ich schon beim
Delphi-Quellcode:
aFileStream.Free;
eine Exception erwartet hätte.
Hmmmm, aber vielleicht hatte es ja dort geknallt und der Debugger zeigte nur die falsche Codezeile an. (macht er gerne mal, da der Stacktrace die Rücksprungadressen behinhaltet, also den nächsten Befehl)


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:34 Uhr.
Seite 3 von 3     123   

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz