AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi DataSnap - Zugriff von WebProjekt

DataSnap - Zugriff von WebProjekt

Ein Thema von himitsu · begonnen am 29. Jun 2020 · letzter Beitrag vom 30. Jun 2020
Antwort Antwort
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
36.330 Beiträge
 
Delphi 10.4 Sydney
 
#1

DataSnap - Zugriff von WebProjekt

  Alt 29. Jun 2020, 13:58
Falls jemand weiß wie man da mit JavaScript Binärdaten überträgt, wäre es schön zu wissen,
denn die bestehende Serverstruktur weiterverwenden zu können, für die neue zusätzliche Webanwendung, das wäre doch zu praktisch.
* Dokumente abrufen und anzeigen (das Ginge)
* Foto machen oder Datei einlesen und übertragen (das knallt)

Also, damals vor vielen Jahren einen DataSnap-Server implementiert und bissl angepasst.
Wir haben noch eine Zwischenschicht im DataSnap drin, welche beim Empfänger (Client und Server) die TStreams von dem blöden DataSnap-Stream in ein TMemoryStream umkopiert, weil viele Dinge mit dem Size=-1 nicht klar kommen, was bei größeren Streams ankommt, wenn DataSnap die Daten beim Auslesen stückweise nachlädt.
Und auch TDataSets hatten wir damals nochmal überarbeitet, weil es bei größeren TEXTen Probleme gab, im Zusammenhang mit DevExpressGrids und dessen DataController. (TEXT in VARCHAR konvertiert, vor Übergabe in dem DBXDataSetStreamingzeugs, bzw. den Code kopiert und da die Typen ausgetauscht).

Das lief bisher problemlos binär, also via TCP/IP (TDSTCPServerTransport2), bzw. intern mit dbExpress,
und nun hatte noch den TDSHTTPService nachgerüstet.

Aber dort habe ich nun Probleme beim Abruf.
Erstmal wird die AuthentificationMethode doppelt aufgerufen und beim zweiten Mal mit NIL im Parameter (ist bekannt, denn viele hatten das Problem schon),
was bissl blöd ist, wenn man auf den Parameter zugreift, um darin Nutzername und Passwort zu prüfen. (gut, da der erste Durchlauf ausreicht, überspring ich das einfach ... if not assigned then exit)

Schlimmer ist aber, dass ich ums verrecken nicht alle Funktionen aufgerufen bekomme, vorallem da nicht wo in TStream reingegeben werden soll.

[EDIT]
Da hing wohl ein Haltepunkt etwas.
Grade nochmal alles ohne Eurekalog kompiliert, und nun gesehen dass unsere TDSFileMethods.WriteFile erfolgreich aufgerufen und ausgeführt wird,
aber nach dem END; der Methode knallt es dann irgendwo.
[/EDIT]

* Danke erstmal an Eurekalog, dass ihr einem ständig beim Debuggen das Leben erschwert.
* nach Loswerden des Mistdings nun "irgendwo" die Fehlerstelle in der DataSnapServer150.bpl verordet, aber k.A. warum.
(ja, der Umstieg auf 10.2 ähhh 10.3 10.4 ist schon geplant)

Zuerst hab ich mir mal schnell eine Clientanwendung generieren lassen
und wollte mir im Server das Protokoll loggen, um zu sehen was wie übergeben werden muß,
aber leider knallt es jetzt schon.

Beim Debuggen und aus dem generierten Client ist zu erkennen, dass "leider" der Stream als JSON via HTTP-POST übergeben werden muß.
Gut, unser Webentwickler wäre damit schon zufrieden, falls ich es hinbekomm dass es funktioniert, und wenn man rausbekommt wie die Binärdaten da codiert werden müssen.
Gefragt hatte er aber auch zuerst, ob wir z.b. auch MultiPart-POSTs als über einen REST-Serverannehmen können, wobei mir dann erstmal einfiel, dass DataSnap auch RESTful ist und so wollte ich erstmal schauen was damit geht, weil der schon da ist.

Das Format des JSON, bzw. die zwei Möglichen der Parameterübergabe sind teilweise aus der Doku zu entnehmen, jedenfalls das grundlegende Format, aber nicht der einzelnen Datentypen.
http://docwiki.embarcadero.com/RADSt...gen_entwickeln
http://docwiki.embarcadero.com/RADSt...nd_Architektur
http://docwiki.embarcadero.com/RADSt.../DataSnap-REST
http://docwiki.embarcadero.com/RADSt...chtenprotokoll
http://docwiki.embarcadero.com/RADSt...ientbibliothek
* Hab ich beide probiert, es knallte, also hab ich den TestClient neu generieren lassen.

SO, hier die 3 Testfunktionen des DataSnap-Servers:
[DELPHI]function TDSServerMethods.ReverseString(S: String): String;
function TDSFileMethods.ReadFile(Filename: String): TStream;
procedure TDSFileMethods.WriteFile(Filename: String; Stream: TStream);[DELPHI]
Und Letztere knallt leider.

Wenn nichts geht, muß ich wohl selbst codieren (z.B. Base64) und es als "String" übergeben lassen.

Über https://apitester.com/ bissl rumprobiert:
Code:
GET /DataSnap/REST/TDSServerMethods/ReverseString/ABC12345 HTTP/1.1
Host: *****:8080
Accept: */*
User-Agent: Mozilla/5.0 (compatible; Rigor/1.0.0; http://rigor.com)
Authorization: Basic *****
Code:
HTTP/1.1 200 OK
Connection: close
Content-Type: text/html; charset=ISO-8859-1
Content-Length: 23
Pragma: dssession=305680.375499.525712,dssessionexpires=1200000
Server: DatasnapHTTPService/2011

{"result":["54321CBA"]}
oder
Code:
GET /DataSnap/REST/TDSFileMethods/ReadFile/rechnung\1192.pdf HTTP/1.1
Host: pg.prodat-erp.de:8080
Accept: */*
User-Agent: Mozilla/5.0 (compatible; Rigor/1.0.0; http://rigor.com)
Authorization: Basic *****
Code:
HTTP/1.1 200 OK
Connection: close
Content-Type: text/html; charset=ISO-8859-1
Content-Length: 194106
Pragma: dssession=407731.981971.840684,dssessionexpires=1200000
Server: DatasnapHTTPService/2011

%PDF-1.7
%âãÏÓ
2 0 obj
<</Length 3532/Filter/FlateDecode>>
stream
xÅ[Én$ǽ7ÐÿPg,çZ`4@&#381;8|³=&#8364;&#8218;n¶&#8211;&#8364;ÑÅ¿ï÷"2²*«ºÉ^&#8224;Ò¡Y[.±¼X23øõxøûñðõÜß4N½C7ø©O&#402;ïð&#732;¦.O}î~û÷ñðýñðëñðòåxøóg×Íýìº/ÿ9~ø±sÝ¿&#381;&#8225;&#8249;ë~ûéxHSî&#8225;Ô
Cî3ÚàÛ_&#339;&#8249;Ù¹ðì&#339;ÇÕGü\¹ò&#382;¿¿ñÔ}ùùxxÅ7Ì&#8220;Sï&#8217;ÍãÆ&#8482;ðÃu\ÞÛ¼r½k&#382;ú<*çq ;&#402;îð#Cä#Ý5vô½6v!+òðéß|×\~î&#8225;ÁæyQf¦&#8225;¸&#338;¹J
...
GET-Abrufe funktionieren erstmal.

Und ja, bemerkenswert ist, dass DataSnap immer von "text/html" redet, egal ob es REST/JSON oder Binärdaten ausliefert.

Im Gegenzug ist es auch vollkommen egal, was ich als Content-Type übergeben, es wird immer als JSON interpretiert,
denn wenn ich versuche es wie beim Abruf binär zu übergeben, dann
Code:
POST /DataSnap/REST/TDSFileMethods/%22WriteFile%22/rechnung%5C1192.pdf HTTP/1.1
Host: pg.prodat-erp.de:8080
Accept: */*
User-Agent: Mozilla/5.0 (compatible; Rigor/1.0.0; [url]http://rigor.com[/url])
Authorization: Basic *****
Content-Type: application/octet-stream
Content-Length: 194106

%PDF-1.7
%âãÏÓ
2 0 obj
...
Code:
HTTP/1.1 500 Interner Server-Fehler
Connection: close
Content-Type: text/html; charset=ISO-8859-1
Content-Length: 93
Pragma: dssession=982145.594458.865431,dssessionexpires=1200000
Server: DatasnapHTTPService/2011

{"error":"JSON-Werteingabe %PDF-1.7.... kann nicht in TDBXTypes.UNKNOWN(33) konvertiert werden"}
also
Code:
POST /DataSnap/REST/TDSFileMethods HTTP/1.1
Host: pg.prodat-erp.de:8080
Accept: */*
User-Agent: Mozilla/5.0 (compatible; Rigor/1.0.0; http://rigor.com)
Authorization: Basic *****
Content-Length: 88
Content-Type: application/x-www-form-urlencoded

{"_parameters":["rechnung\\1192__.pdf", "123456789"]}
oder
Code:
...
{"filename":"rechnung\\1192__.pdf", "stream":"123456789"}
oder mit filename in der URI
Code:
...
{"stream":"123456789"}
Code:
HTTP/1.1 500 Interner Server-Fehler
Connection: close
Content-Type: text/html; charset=ISO-8859-1
Content-Length: 89
Pragma: dssession=144988.358193.280590,dssessionexpires=1200000
Server: DatasnapHTTPService/2011

Zugriffsverletzung bei Adresse 5003A116 in Modul 'rtl150.bpl'. Lesen von Adresse 00000001
Zitat:
:74ddc562 KERNELBASE.RaiseException + 0x62
:5003a0d5 TObject.FreeInstance + $11
:5003a0d5 TObject.FreeInstance + $11
:51fa5d92 Generics + $445D92
:51fa1169 Generics + $441169
:51fa1cb8 Generics + $441CB8
:51ff2081 Generics + $492081
:50bb76c8 TIdCustomHTTPServer.DoCommandGet + $20
:50bb8639 TIdCustomHTTPServer.DoExecute + $591
:50ab794a TIdContext.Run + $12
:500acc4d ThreadProc + $45
:5003bf42 ThreadWrapper + $2A
:779f62c4 KERNEL32.BaseThreadInitThunk + 0x24
:77d30969 ;
:77d30934 ;
51fxxxxx ist die DataSnapServer150.bpl

[EDIT]
Also unsere Methode ist durchgelaufen und nach dem END hab ich mich nun mühsam mit F7/F8 durchgekämpft.
Im zweiten oder dritten Generis+xxx (DataSnapServer150.bpl) knallt es dann, scheinbar am Ende einer Methode, beim Freigeben eines "Records", im zweiten Eintrag, bei der Speicherfreigabe.
EInvalidPointer (Ungültige Zeigeroperation) oft gefolgt von zwei oder drei dutzend Indy- und DBX-Exceptions.
Zitat:
:51fe980a TDSServerMethod.Invoke + $1E2
:51fe9d25 TDSServerMethodCommandHandler.DbxExecute + $19D
:51fe944b TDSServerConnectionHandler.DbxExecute + $27
:51fe784d TDSServerCommand.DerivedExecuteUpdate + $5
:51f78ac6 Generics + $418AC6
:51f787c1 Generics + $4187C1
:51f7929c Generics + $41929C
:51f794b4 Generics + $4194B4
:51fa1050 Generics + $441050
:51fa1cb8 Generics + $441CB8
:51ff2081 Generics + $492081
:50bb76c8 TIdCustomHTTPServer.DoCommandGet + $20
[/EDIT]


Im Moment weiß ich einfach nicht mehr weiter.
Die Methoden mit dem TCPIP-Client funktionieren seit Jahren,
aber über den HTTP-TunnelService raucht ein Teil grandios ab.

Aus dem neuen Testclient
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  X: TStream;
  S: string;
begin
  {
  S := ClientModule1.DSServerMethodsClient.ReverseString('abc123');
  if S = '321abc' then
    ;

  X := ClientModule1.DSFileMethodsClient.ReadFile('rechnung\1192.pdf');
  if X.Size > 0 then
    ;
  X.Free;
  }


  S := '12345';
  X := TMemoryStream.Create;
  X.Write(S[1], 10);
  X.Position := 0;
  ClientModule1.DSFileMethodsClient.WriteFile('rechnung\1192.pdf', X);
  X.Free;
end;
und der automatisch generierte Code dazu
Delphi-Quellcode:
procedure TDSFileMethodsClient.WriteFile(Filename: string; Stream: TStream);
begin
  if FWriteFileCommand = nil then
  begin
    FWriteFileCommand := FConnection.CreateCommand;
    FWriteFileCommand.RequestType := 'POST';
    FWriteFileCommand.Text := 'TDSFileMethods."WriteFile"';
    FWriteFileCommand.Prepare(TDSFileMethods_WriteFile);
  end;
  FWriteFileCommand.Parameters[0].Value.SetWideString(Filename);
  FWriteFileCommand.Parameters[1].Value.SetStream(Stream, FInstanceOwner);
  FWriteFileCommand.Execute;
end;
POST ist also richtig
und beim Debuggen von FWriteFileCommand.Execute ist zu erkennen, dass es als zwei Parameter in JASON verpackt wird.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
Delphi-Tage 2005-2014

Geändert von himitsu (29. Jun 2020 um 16:26 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
36.330 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: DataSnap - Zugriff von WebProjekt

  Alt 30. Jun 2020, 17:32
So, nach paar Tagen genervter Suche, endlich eine Lösung.
  • DataSnap ist blöd ... im XE über HTTP-REST (keine Lust das jetzt noch auf neuem Delphi zu probieren .... wird bestimmt eh noch ein Spaß DataSnap von XE auf 10.4 zu migrieren)
  • TStream-Parameter abrufen geht
  • TStream-Parameter senden knallt immer, egal ob aus neue generiertem DataSnap-Client oder manuell
  • abgerufen mit nur einem Result-Parameter "TStream" kommt es binär beim Client an (also perfekt, auch wenn der Content-Typ von "text/html; charset=ISO-8859-1" schwafelt, obwohl es Binädaten sind, wie z.B. ein PDF)
  • gesendet wird es als JSON-Array mit millionen Values/Integern ... je ein Integer pro Byte
  • abgesehn davon dass es nicht funktioniert (Exception NACH meiner DataSnap-Methode, selbst, vermutlich wenn anschließend der TStream freigegeben wird),
    lacht sich unser WebEntwickler doch mindestens zu tode und macht sich über Delphi/DataSnap lustig, wenn ich ihm sage wie das Format aussieht

Ich hab mich nun mühevoll durch das Senden des DataSnap-HTTP/REST-Clienten gekämpft und geschaut was gesendet wird.
Ja, es gibt eine nette Trace-Methode im Server, wo man das Protokoll loggen kann, allerdings wird die erst NACH der Verarbeitung aufgerufen, wo man dann Request und Response einsehen kann, aber da es schon vorher knallt und abraucht .........

TDSRestCommand.Execute
ExecuteCommand (DSClientRest)
ExecuteRequest (DSClientRest)
LParametersToSendInContent:=
ExecuteRequest> ParameterToJSon
TDBXJSONTools.StreamToJSON
Dabei ensteht ein JSON-Array mit sehr vielen Values/Integern pro Byte, locker 3 bis 4 Mal so viele Daten wie die Datei groß ist.

procedure TDSFileMethods.WriteFile(Filename: String; Stream: TStream);
Zitat von 10 Byte-Datei:
POST /DataSnap/REST/TDSFileMethods/%22WriteFile%22/rechnung%5C1192.pdf HTTP/1.1
Host: ***
Authorization: Basic ***
Accept: application/JSON
Content-Type: text/plain;charset=UTF-8
If-Modified-Since: Mon, 1 Oct 1990 05:00:00 GMT
Content-Length: 26

[0,1,2,3,4,5,6,32,128,255]
Ich würde jetzt einfach die Datei als Base64 in einem JSON-String entgegen nehmen.

Mit einem Delphi-Client könnte ich meine Lösung nicht umsetzen, da DataSnap alle String-Parameter ohne Längenprüfung in die URL einbaut (in XE) und nur Tabellen/Streams/Json als JSON via POST sendet (siehe ExecuteRequest und IsUrlParameter in DSClientRest),
aber zum Glück kann man das bei manuellem REST-Aufruf das anpassen (eine beliebige Anzahl der Parameter in der URL und ab beliebiger Quelle geht's weiter im JSON-Request).

Wichtig ist aber dass man Accept und Content-Type nicht vergisst, denn so wie im Response der Content-Type totaler Schwachsinn ist, darf man ihm im Request aber nicht vergessen, sonst werden die POST-Daten zwar zwangsweise als JSON entgegen genommen (oder es knallt) aber dann einfach still und heimlich ignoriert (POST-Parameter bleiben leer und TStream ist nil).

Hab das mal mit ReverseString ausprobiert
function TDSServerMethods.ReverseString(S: String): String;
Zitat:
GET /DataSnap/REST/TDSServerMethods/ReverseString/ABC12345 HTTP/1.1
Host: *****
Accept: */*
Authorization: Basic *****
Zitat:
POST /DataSnap/REST/TDSFileMethods/%22ReverseString%22 HTTP/1.1
Host: *****
Authorization: Basic *****
Accept: application/JSON
Content-Type: text/plain;charset=UTF-8
If-Modified-Since: Mon, 1 Oct 1990 05:00:00 GMT
Content-Length: 29

{"_parameters":["123456789"]}
liefert Beides
Zitat:
{"result":["987654321"]}
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
Delphi-Tage 2005-2014

Geändert von himitsu (30. Jun 2020 um 18:13 Uhr)
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 10:29 Uhr.
Powered by vBulletin® Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2020 by Daniel R. Wolf