Link to home
Start Free TrialLog in
Avatar of Stef Merlijn
Stef MerlijnFlag for Netherlands

asked on

Translate VB-code to Delphi

Hi,

Below part of some VB.Net code is shown. It is used to interface data to an online application via SOAP.
The full code can be downloaded here
First some info: Code from de WDSL:
    function CreateStamTabelRecord(const PartnerKey: string; const Omgevingscode: string; const SessionId: string; const Stamtabel: Stamtabel; var Primarykey: string; var Foutmelding: string): Boolean; stdcall;

Open in new window

  Stamtabel = class(TRemotable)
  private
    Fschema: TXMLData;
  public
    destructor Destroy; override;
  published
    property schema: TXMLData  Index (IS_REF) read Fschema write Fschema;
  end;

Open in new window


Can anybody translate the following VB-code to Delphi?
The content of ds_mutatie is important to be correct. How should this be created within Delphi?
Private Sub btnCreateNewDeb_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCreateNewDeb.Click
        If String.IsNullOrEmpty(txtSessionId.Text) Then MsgBox("SessionId is leeg.") : Exit Sub

        Select Case combometh.SelectedItem
            Case "SOAP"
                Dim ws1 As New ws1.ws1
                Dim foutmelding As String = ""
                Dim ds_records As New DataSet

                Dim ds_mutatie As New DataSet
                Dim dt_selection As DataTable = ds_mutatie.Tables.Add : dt_selection.TableName = "METADATA"
                dt_selection.Columns.Add("TABLE", GetType(System.String)).DefaultValue = "DEB"
                Dim dr_selection = dt_selection.NewRow : dt_selection.Rows.Add(dr_selection)

                Dim dt_data As DataTable = ds_mutatie.Tables.Add : dt_data.TableName = "DATA"
                dt_data.Columns.Add("ZKSL", GetType(System.String)).DefaultValue = txtZKSLNieuw.Text

                Dim dr_data = dt_data.NewRow : dt_data.Rows.Add(dr_data)

                Dim MessageId() As String = Nothing
                If Not ws1.CreateStamTabelRecord(txtPartnerKey.Text, txtOmgevingsCode.Text, txtSessionId.Text, ds_mutatie, txtNrNieuw.Text, foutmelding) Then
                    MsgBox("debiteur aangemaakt mislukt: " + foutmelding)
                Else
                    MsgBox("debiteur aangemaakt, deb.nr: " + txtNrNieuw.Text)
                    txtDebNr.Text = txtNrNieuw.Text
                End If
        End Select
    End Sub

Open in new window

<NewDataSet>
<METADATA>
<TABLE>DEB</TABLE>
</METADATA>
<DATA>
<ZKSL>naam debiteur</ZKSL>
</DATA>
</NewDataSet>

Open in new window

Avatar of ste5an
ste5an
Flag of Germany image

This is completely the wrong track.

Just import the WSDL and let Delphi generate the code: Using the WSDL Importer.
Avatar of Stef Merlijn

ASKER

I did already import the WDSL in Delphi.
The problem is how to fill the data, as in the VB-example.
Just provide the information necessary to execute that method. But I guess your problem is the DataSet parameter? How is it tranlated in Delphi? You need to make a runnable VB sample to examine with a sniffer how it is translated. The .NET datasets have a ToXML method. So maybe this format is used..
Yes, ds_mutatie (dataset) gives me the headache.
Therefor I hoped someone could understand how VB.Net set this up and translate it to Delphi.
As far as I know the content of the DataSet should reflect to XML-code I posted at the bottom. Elements from that also ocur in the VB.Net code.
I just need to know how to convert that code.

I have Visual Studio installed in order to run the provided VB.Net example, but I'm not able to figure it out.
The problem is that this web service uses a .NET class as method parameter. Which is a bad idea from the web service author. Cause now the web service depends on how .NET serialzes this data type, the data set.

I woul guess the dataset is serialized into the default XML dataset representation also used when using the dataset GetXml() method.

But you need to verify this first. Thus you need a working VB sample client. Then you need to sniff the traffic to see how it is really serialized.
ds_mutatie is of class Stamtabel which is a TXMLData (declaration is also mentioned in my first post).
Till now I came up with something like this:
procedure TForm1.btDebiteurMakenClick(Sender: TObject);
var lError: string;
    IDforNewRecord : String;
    ds_mutatie : Stamtabel;
    xData : TXMLData;
begin
  IDforNewRecord := '18888';
//  ds_mutatie := Stamtabel.Create; // uses Soap.XSBuiltIns
//  ds_mutatie.schema.LoadFromXML(Memo1.Lines.text);  // here is the xml content to send
//  xData := TXMLData.Create;    // uses Soap.XSBuiltIns
//  xData.LoadFromXML(Memo1.Lines.text);  // here is the xml content to send
//  ds_mutatie.Schema := xData.ToString;
  if NOT ws1.CreateStamTabelRecord(cPartnerKey , cOmgevingsCode , fSessionId , ds_mutatie, IDforNewRecord, lError) then
    MessageDlg('Create record error: ' + lError, TMsgDlgType.mtError , [mbOK] , 0)
  else
    ShowMessage('Debtor is created: ' + IDforNewRecord)
end;

Open in new window

CONTENT of Memo1:
<NewDataSet>
<METADATA>
<TABLE>DEB</TABLE>
</METADATA>
<DATA>
<NR>18888</NR>
<ZKSL>test debiteur</ZKSL>
<NAAM>Test debiteur</NAAM>
<STRAAT>De Trompet</STRAAT>
<HNR>2880</HNR>
<HNRTV>A</HNRTV>
<POSTCD>1967 DD</POSTCD>
<PLAATS>Heemskerk</PLAATS
><LAND>NL</LAND>
<TEL>0251-241641</TEL>
<FAX>0251-244405</FAX>
<EMAIL>info@muis.nl</EMAIL>
<HOMEPAGE>http://www.muis.nl</HOMEPAGE>
<BNKIBAN>NL38RABO0123456800</BNKIBAN>
<BETALER>10001</BETALER>
<BETCOND>1</BETCOND>
<BTWPL>B</BTWPL>
<BTWNR>NL123436771B01</BTWNR>
<KVKNR>54543737</KVKNR>
</DATA>
</NewDataSet>

Open in new window

This is my example:
procedure TForm1.Button1Click(Sender: TObject);
var
  ws1: ws1_xmlSoap;
  foutmelding, Primarykey, Stamtabel: String;
begin
  if Length(txtSessionId.Text) = 0 then
  begin
    ShowMessage('SessionId is leeg.');
    Exit;
  end;

  foutmelding := '';
  Primarykey := '';

  Stamtabel := '';
  Stamtabel := Stamtabel + '<NewDataSet>' + #13#10;
  Stamtabel := Stamtabel + '<METADATA>' + #13#10;
  Stamtabel := Stamtabel + '<TABLE>'+'DEB'+'</TABLE>' + #13#10;
  Stamtabel := Stamtabel + '</METADATA>' + #13#10;
  Stamtabel := Stamtabel + '<DATA>' + #13#10;
  Stamtabel := Stamtabel + '<ZKSL>naam debiteur</ZKSL>' + #13#10;
  Stamtabel := Stamtabel + '</DATA>' + #13#10;
  Stamtabel := Stamtabel + '</NewDataSet>';

  //create soap call
  ws1 := Getws1_xmlSoap();
  try
    //need to call Login first ...
    if not ws1.CreateStamTabelRecord(txtPartnerKey.Text, txtOmgevingsCode.Text, txtSessionId.Text,
      Stamtabel, Primarykey, foutmelding) then
    begin
      ShowMessage('debiteur aangemaakt mislukt: ' + foutmelding);
    end
    else
    begin
      ShowMessage('debiteur aangemaakt, deb.nr: ' + txtNrNieuw.Text);
      txtDebNr.Text := txtNrNieuw.Text;
    end;
  finally
    ws1 := nil;
  end;
end;

Open in new window


note... I assume that you need to call Login first... and before that obtain PartnerKey and Omgevingscode...
Using soap is a quite easy ...
...and main thing is to build proper xml definition of a table/row/data string.
A dataset is not strongly typed. You can pass any kind of dataset, thus any XML. Either you ask the web service provider for the correct data set layout or you try and error..
Thus you need a working VB sample client.
Got that already.

Then you need to sniff the traffic to see how it is really serialized.
How would I do that?
Using Fiddler you can sniff traffic, and look how soap/xml looks like...
Either using Fiddler or Wireshark. The first is a HTTP/HTTPS sniffer, the second a generic one.

Using Fiddler to capture SOAP messages

Caveat: both tools should be only installed on development machines. Never on production.
procedure TForm1.btDebiteurMakenClick(Sender: TObject);
var lError: string;
    IDforNewRecord : String;
    v_Stamtabel : String;
    ds_Stamtabel : Stamtabel;
begin
  v_Stamtabel := '';
  v_Stamtabel := v_Stamtabel + '<NewDataSet>' + #13#10;
  v_Stamtabel := v_Stamtabel + '<METADATA>' + #13#10;
  v_Stamtabel := v_Stamtabel + '<TABLE>'+'DEB'+'</TABLE>' + #13#10;
  v_Stamtabel := v_Stamtabel + '</METADATA>' + #13#10;
  v_Stamtabel := v_Stamtabel + '<DATA>' + #13#10;
  v_Stamtabel := v_Stamtabel + '<NR>18888</NR>' + #13#10;
  v_Stamtabel := v_Stamtabel + '<ZKSL>naam debiteur</ZKSL>' + #13#10;
  v_Stamtabel := v_Stamtabel + '<NAAM>naam debiteur</NAAM>' + #13#10;
  v_Stamtabel := v_Stamtabel + '</DATA>' + #13#10;
  v_Stamtabel := v_Stamtabel + '</NewDataSet>';
  ds_Stamtabel := Stamtabel.Create; // uses Soap.XSBuiltIns
  //  AND HERE ???
  //  I need to assign the content of v_Stamtabel (String) to ds_Stamtabel (Stamtabel = TXMLData) ?

Open in new window

E.g.

Stamtabel := TXMLData.Create;
Stamtabel.LoadFromXML(v_Stamtabel);

Open in new window

Stamtabel doesn't have a LoadFromXML.
[dcc32 Error] Unit1.pas(187): E2003 Undeclared identifier: 'LoadFromXML'
  Stamtabel = class(TRemotable)
  private
    Fschema: TXMLData;
  public
    destructor Destroy; override;
  published
    property schema: TXMLData  Index (IS_REF) read Fschema write Fschema;
  end;

Open in new window

Try writing it to schema.
If it only was so easy Pfff
  ds_Stamtabel := Stamtabel.Create; // uses Soap.XSBuiltIns
  ds_Stamtabel.schema.LoadFromXML(v_Stamtabel);

Open in new window

Exception at this code in unit Soap.XSBuiltIns
procedure TXMLData.LoadFromXML(const XML: string);
begin
  FXMLDocument.LoadFromXML(XML);
  if FXMLDocument.Node.ChildNodes.Count > 0 then
    FXMLNode := FXMLDocument.Node.ChildNodes[0];
end;

Open in new window

What exception?
Access Violation Read of Address
ASKER CERTIFIED SOLUTION
Avatar of Stef Merlijn
Stef Merlijn
Flag of Netherlands image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
None of the other proposed solutions solved my issue.