AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi Datasnap File Upload
Thema durchsuchen
Ansicht
Themen-Optionen

Datasnap File Upload

Ein Thema von BeBored · begonnen am 3. Dez 2011 · letzter Beitrag vom 12. Sep 2012
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.342 Beiträge
 
Delphi 12 Athens
 
#1

AW: Datasnap File Upload

  Alt 10. Jan 2012, 12:51
Der Tipp mit der Abfrage nach dem InstanceOwner war sehr hilfreich, sie liefert hier True.
TRUE ist halt die Standardeinstellung bei dieser automatisch generierten Klasse.

Allerdings ist mir nicht klar, warum der InstanceOwner des Streams hier das DataModule ist. Kann man das irgendwo einstellen?
Genau dort, wo ich es auch abfrage?
(das ist die globale Einstellung für sowas)

Dieser Wert wird vor den automatisch generierten Clientklassen abgefragt und jeweils für deren Objekt-Parameter verwendet.
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Gor1

Registriert seit: 11. Mai 2011
32 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: Datasnap File Upload

  Alt 11. Jan 2012, 10:51
Danke für deine Hilfe, ich habe die entsprechenden Stellen jetzt gefunden.
  Mit Zitat antworten Zitat
Benutzerbild von Captnemo
Captnemo

Registriert seit: 27. Jan 2003
Ort: Bodenwerder
1.126 Beiträge
 
Delphi XE4 Architect
 
#3

AW: Datasnap File Upload

  Alt 12. Sep 2012, 07:53
Hallo,

ich habe mir eure Funktion oben mal zu nutze gemacht um ein Bild zu übertragen. Klappt auch im Großen und Ganzen wunderbar.
Nur habe ich an einer Stelle einen Fehler, den ich mir nicht erklären kann. Hier erst mal mein Code im Client:
Delphi-Quellcode:
procedure TForm2.Button2Click(Sender: TObject);
var
  aClient: TServerMethods1Client;
  aFileStream: TFileStream;
  i: Integer;
 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;
(Jetzt bitte mal nicht auf die Try...expept-Blöcke achten )

Wenn ich jetzt was übertragen will, dann tritt beim aClient.Free eine Exception auf:
"Im Projekt DSClient.exe ist eine Exception der Klasse $C0000008 mit der Meldung 'system exception (code 0xc0000008) at
0x77b712f7' aufgetreten."

Ich war eigentlich immer der Meinung, dass man selbst erzeugte Objekte auch selber wieder freigeben sollte. Aber möglicherweise
besteht ja noch ein Zugriff auf dieses Objekt. Ich weiß aber nich wo.

Wenn ich das aClient.Free weglasse, dann habe ich bei XP beim verlassen des Programms eine Exception:
"Exception EAccessViolation in Modul DSClient.exe bei 00005D08.
Zugriffsverletzung bei Adresse 00405D08 in Modul 'DSClient.exe'. Lesen von Adresse 0000000C."

Ich habe noch eine zweite Funktion, die ich aus einen Tutorial übernommen habe:
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;
Die läuft aber ohne Exception, und hier gehe ich aClient ja auch frei.

Hat jemand eine Idee, was ich falsch gemacht habe?
Dieter
9 von 10 Stimmen in meinem Kopf sagen ich bin nicht verrückt. Die 10. summt dazu die Melodie von Supermario Bros.
MfG Captnemo
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.629 Beiträge
 
Delphi 12 Athens
 
#4

AW: Datasnap File Upload

  Alt 12. Sep 2012, 09:18
      aClient.UploadFile(aFileStream, 'Upload', ExtractFileName(JvFilenameEdit1.Text));
Zeig mal, was da in UploadFile passiert.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.629 Beiträge
 
Delphi 12 Athens
 
#5

AW: Datasnap File Upload

  Alt 12. Sep 2012, 09:44
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.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von Captnemo
Captnemo

Registriert seit: 27. Jan 2003
Ort: Bodenwerder
1.126 Beiträge
 
Delphi XE4 Architect
 
#6

AW: Datasnap File Upload

  Alt 12. Sep 2012, 10:54
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.
Dieter
9 von 10 Stimmen in meinem Kopf sagen ich bin nicht verrückt. Die 10. summt dazu die Melodie von Supermario Bros.
MfG Captnemo
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.629 Beiträge
 
Delphi 12 Athens
 
#7

AW: Datasnap File Upload

  Alt 12. Sep 2012, 12:30
  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.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.342 Beiträge
 
Delphi 12 Athens
 
#8

AW: Datasnap File Upload

  Alt 12. Sep 2012, 13:23
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 aFileStream.Free; und aClient.Free; , oder kommentiere aFileStream.Free; aus.

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

In einer der automatisch generierten Clientklassen baut Delphi ein Property ein, wo du dieses Freigeben deaktivieren kannst.
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.629 Beiträge
 
Delphi 12 Athens
 
#9

AW: Datasnap File Upload

  Alt 12. Sep 2012, 13:42
Vertausche mal aFileStream.Free; und aClient.Free;
Jetzt nicht wirklich, oder? Die Instanz wird zwar automatisch freigegeben, aber die Variable aFileStream wird damit nicht zwangsläufig auf nil gesetzt.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.342 Beiträge
 
Delphi 12 Athens
 
#10

AW: Datasnap File Upload

  Alt 12. Sep 2012, 13:51
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 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)
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:08 Uhr.
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