ertank 27 Posted October 26, 2018 (edited) Hello, I tried to find solution to my problem in several places already including stackoverflow When consuming a SOAP web service, response to a request comes in fine, but it is not populated in response object in code. I already provided details in above link. Let me know if they really need to be in this post, please. I added all files needed to test my case. I did not provide username and password as they are irrelevant to my problem. Below is an example code to use provided units. uses EFinans.EArsivFatura; procedure TForm1.Button1Click(Sender: TObject); var Input: TFaturaOlusturInput; begin // required before calling any EFinans.EArsivFatura procedure/function EFinans.EArsivFatura.URLEArsivFatura := 'https://earsiv.efinans.com.tr/earsiv/ws/EarsivWebService'; EFinans.EArsivFatura.Username := 'someuser'; EFinans.EArsivFatura.Password := 'somepassword'; // preparing parameters Input.donenBelgeFormati := Ord(TGelenBelgeFormatlari.gePDF); Input.goruntuOlusturulsunMu := 1; // 0=hayır, 1=evet Input.islemId := TGUID.NewGuid.ToString().Substring(1, 36).ToLower(); Input.vkn := '123456789'; Input.sube := '000000'; Input.kasa := '0000'; Input.numaraVerilsinMi := 0; Input.faturaSeri := EmptyStr; Input.sablonAdi := 'einvoice_efinans_15_06_04_3.xslt'; Input.erpKodu := 'ERP1'; Input.gzip := 1; if not EFinans.EArsivFatura.AFaturaOlustur(Input, TGidenBelgeFormatlari.PDF, 'test.zip', 'test.pdf') then begin ShowMessage(EFinans.EArsivFatura.LastError); Exit(); end; end; Above sample code will get you an error response from web service. That response will be saved in "response.xml" file in same directory as your EXE. If you debug and put a break point in line 237 of EFinans.EArsivFatura.pas you should see that Response.return is nil. That is my problem. I have same problem in other methods, too. Just trying to see how I fix this single one now. Thanks & regards, Ertan EarsivWebService1.pas EFinans.EarsivFatura.Utils.pas EFinans.EArsivFatura.pas response.xml test.zip Edited October 26, 2018 by ertank Put additional details Share this post Link to post
Michael Puff 18 Posted October 26, 2018 Please provide the details here as well. Thank you. Sherlock added: Even though most users are members of several services, for highest impact you should post the complete question here as well. Perhaps the person that could really help you is not a StackOverflow member, and can't read your post there. Share this post Link to post
Sherlock 663 Posted October 26, 2018 As I remarked in StackOverflow, that WSDL is quite complex and unusual. Have you created the SOAP service? Share this post Link to post
ertank 27 Posted October 26, 2018 SOAP service side is most likely prepared in C#. Not my web service at all. This is an electronic invoice service provider. Company between government and developers. Share this post Link to post
Guest Posted October 27, 2018 (edited) I'm not sure this is helpful... I remember many years back I faced similar problems. I think I wanted to consume from Exchange Web Services. After ditching Delphi's own stuff I went Rem-objects. There was support and they tried but concluded that the schema was too advanced or Microsoft-y or maybe to C-ish. Don't remember. Anyhow, to the point; I downloaded the Visual Studio free and wrote a small dll that I used in Delphi with AtoZ's CrossTalk all the array handling and advanced properties that no Delphi-native lib could handle was no problem whatsoever. IMHO once you solve this problem, the next pops up. My recommendation is talk to C# soap/wdsl with C# and so on. It's simply to ORMish to translate well. HTH, (flame suit on)... /D (phone) Edited October 27, 2018 by Guest Share this post Link to post
mausmb 13 Posted October 28, 2018 (edited) On 10/26/2018 at 11:12 AM, ertank said: SOAP service side is most likely prepared in C#. Not my web service at all. This is an electronic invoice service provider. Company between government and developers. Hi, This SOAP web service can't be imported in Delphi via WSDL importer 😞 Without import you can't use it directly If you don't understand all objects ... Wsdl importer error message "XML document must have a top level element" Line 0. Wsdl is generated with "Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.5-b05 . " and not yours service <!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.5-b05 . --> <!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.5-b05 . --> <definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy"xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"xmlns:tns="http://service.csap.cs.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://service.csap.cs.com/"name="EarsivWebService"> <import namespace="http://service.earsiv.uut.cs.com.tr/" location="https://earsiv.efinans.com.tr:443/earsiv/ws/EarsivWebService?wsdl=1"/> <binding xmlns:ns1="http://service.earsiv.uut.cs.com.tr/" name="EarsivWebServicePortBinding" type="ns1:EarsivWebService"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/> .... Example from c# .Net framework <wsdl:definitions xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="????????" xmlns:s1="http://microsoft.com/wsdl/types/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" targetNamespace="????????"> <wsdl:types> <s:schema elementFormDefault="qualified" targetNamespace="http://ros.si/R16"> <s:import namespace="http://microsoft.com/wsdl/types/"/> My guess is you have also REST available !? Solution : c# import that Service and wrap it to helper service (regular SOAP service) ... and import wrapped WSDL into Delphi regards, M Edited October 28, 2018 by mausmb Share this post Link to post
ertank 27 Posted October 28, 2018 5 hours ago, mausmb said: My guess is you have also REST available !? Solution : c# import that Service and wrap it to helper service (regular SOAP service) ... and import wrapped WSDL into Delphi Unfortunately, I do not have REST version of the same web service. Only SOAP. Probably government enforcement. I will see if I can find anyone familiar with C# and web services. I do not have enough knowledge of C# to import and then wrap for importing WSDL from Delphi. Thanks. Ertan Share this post Link to post
Attila Kovacs 629 Posted October 28, 2018 (edited) Without hacking me into the sources or reading through the thread, did you format the imported wsdl unit in the IDE? Ctrl-D, or 3rd party? Because this wrapper unit is case sensitive and formatting can corrupt it. Edited October 28, 2018 by Attila Kovacs 1 Share this post Link to post
ertank 27 Posted October 28, 2018 23 minutes ago, Attila Kovacs said: Without hacking me into the sources or reading through the thread, did you format the imported wsdl unit in the IDE? Ctrl-D, or 3rd party? Because this wrapper unit is case sensitive and formatting can corrupt it. I did not. I used WSDLImp.exe and unit is what it imported. Code is not formatted. Share this post Link to post
Sherlock 663 Posted October 29, 2018 11 hours ago, Attila Kovacs said: Without hacking me into the sources or reading through the thread, did you format the imported wsdl unit in the IDE? Ctrl-D, or 3rd party? Because this wrapper unit is case sensitive and formatting can corrupt it. Wow! That is good to know. Did not know that. Thanks! Share this post Link to post
ertank 27 Posted October 29, 2018 My knowledge, Delphi does not support namespaces in web services. I now believe, response cannot be parsed by Delphi because both request and response contain "namespaces". I sincerely hope both namespace and easy security header support gets introduced in following versions of Delphi. For now, I give up searching for a solution. I will be generating my own request XML by code, and I will be parsing incoming response XML by code using THTTPRIO.OnBeforeExecute() and THTTPRIO.OnAfterExecute() events. Thanks to everyone. Regards, Ertan Share this post Link to post
TiGü 21 Posted October 31, 2018 (edited) Hi @ertank! I play with your code and do some debugging in the depths of the Delphi SOAP sources. As you can see in the TOPToSoapDomConvert.ProcessResponse (Line 2037 in Tokyo 10.2.3) it calls a inline class helper function IsBareLiteral. Making long story short: Set every time the THTTPRIO.Converter.Options (see Unit Soap.OpConvertOptions) and the Response will be filled. Try this: unit Earsiv.View; interface uses System.SysUtils, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, EarsivWebService1, Soap.SOAPHTTPClient, Soap.OpConvertOptions; type TForm5 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private FRIO: THTTPRIO; WS: EarsivWebService; procedure MyHTTPRIO1AfterExecute(const MethodName: string; SOAPResponse: TStream); public end; var Form5: TForm5; implementation {$R *.dfm} procedure TForm5.Button1Click(Sender: TObject); var Request: faturaOlustur; Response: faturaOlusturResponse; begin if not Assigned(FRIO) then begin FRIO := THTTPRIO.Create(nil); FRIO.OnAfterExecute := MyHTTPRIO1AfterExecute; FRIO.URL := 'https://earsiv.efinans.com.tr/earsiv/ws/EarsivWebService'; // the following line are not enough, see MyHTTPRIO1AfterExecute FRIO.Converter.Options := FRIO.Converter.Options + [soDocument, soLiteralParams]; WS := (FRIO as EarsivWebService); end; Request := nil; Response := nil; Request := faturaOlustur.Create(); Request.input := 'Hello'; Request.fatura := belge.Create(); Request.fatura.belgeFormati := belgeFormatiEnum.PDF; try Response := WS.faturaOlustur(Request); finally if Assigned(Response) and Assigned(Response.return) then begin ShowMessage(Response.return.resultCode + sLineBreak + Response.return.resultText); end; Request.Free; Response.Free; end; end; procedure TForm5.MyHTTPRIO1AfterExecute(const MethodName: string; SOAPResponse: TStream); begin FRIO.Converter.Options := FRIO.Converter.Options + [soDocument, soLiteralParams]; end; end. Edited October 31, 2018 by TiGü 1 Share this post Link to post
TiGü 21 Posted October 31, 2018 Hm, after the first request, the Converter.Options are fine and included soDocument and soLiteralParams...so there is room for improvement (calling MyHTTPRIO1AfterExecute only once and disconnect it afterwards from FRIO.OnAfterExecute or something). Share this post Link to post
TiGü 21 Posted October 31, 2018 Wow, it could be easier. You have to set the Converter.Options after casting to the EarsivWebService interface. Then they are not reset and you can avoid the AfterExecute handler. unit Earsiv.View; interface uses System.SysUtils, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, EarsivWebService1, Soap.SOAPHTTPClient, Soap.OpConvertOptions; type TForm5 = class(TForm) Button1: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private FRIO: THTTPRIO; FEarsivWebService: EarsivWebService; public end; var Form5: TForm5; implementation {$R *.dfm} procedure TForm5.FormCreate(Sender: TObject); begin FRIO := THTTPRIO.Create(nil); FRIO.URL := 'https://earsiv.efinans.com.tr/earsiv/ws/EarsivWebService'; FEarsivWebService := (FRIO as EarsivWebService); FRIO.Converter.Options := FRIO.Converter.Options + [soDocument, soLiteralParams]; end; procedure TForm5.Button1Click(Sender: TObject); var Request: faturaOlustur; Response: faturaOlusturResponse; begin Request := nil; Response := nil; Request := faturaOlustur.Create(); Request.input := 'Hello'; Request.fatura := belge.Create(); Request.fatura.belgeFormati := belgeFormatiEnum.PDF; try Response := FEarsivWebService.faturaOlustur(Request); finally if Assigned(Response) then begin if Assigned(Response.return) then begin ShowMessage(Response.return.resultCode + sLineBreak + Response.return.resultText); end; Response.Free; end; Request.Free; end; end; end. Share this post Link to post