Hope this helps some get to the finish line faster. There is a Webservice Video which is where I got most of this from -- Erel is a very good teacher -- its just .NET SOAP XML is horrible to parse IMO...
Having just went thru this exercise I would provide you my example. I'm attempting to use Classes to contain as much of the interface as I can so it "feels" like .NET
The example I am showing here returns some elements of a menu system containing both a Menu Header and a Menu Detail datatable as a Dataset.
I found that using XML for SOAP web service parsing "too large a mountain to climb" and elected to modify my web service to "also return JSON string" for the dataset which is quite easy using Newtonsoft on the .NET side...
Also, on the web server I am using .NET classes to contain the response - well it made since to me... so its a complex result set (gets more complex with datasets with multiple tables).
Since I also have native PPC and PC application clients, I can't change it - but can add the JSON to it...
Example Class to Setup the consumption of the web service:
Sub Class_Globals
Public MenuID As String
Public ErrorFlag As Boolean
Public ErrorMessage As String
Dim MenuJSON As String
Public MenuDetail As List
Public MenuHeader As List
'
' Controls
'
Public ParseError As Boolean
Public ParseErrorMsg As String
End Sub
'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
ParseError = False
ParseErrorMsg = ""
End Sub
public Sub getRequestXML As String
Return $"<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ReturnMenu xmlns="http://tempuri.org/">
<MenuTransaction>
<MenuID>${MenuID}</MenuID>
</MenuTransaction>
</ReturnMenu>
</soap:Body>
</soap:Envelope>"$
End Sub
public Sub ParseXml(XmlString As String)
Dim x2m As Xml2Map
x2m.Initialize
'
' extract base document root
'
Dim root As Map
If x2m.Parse(XmlString) Is Map Then
root = x2m.Parse(XmlString)
Else
ParseError = True
ParseErrorMsg = "Missing Document Root"
Return
End If
'
' extract base document root
'
'Log(root)
Dim envelope As Map
If root.Get("Envelope") Is Map Then
envelope = root.Get("Envelope")
Else
ParseError = True
ParseErrorMsg = "Soap Envelope Missing"
Return
End If
'
' extract soap body
'
Dim body As Map
If envelope.Get("Body") Is Map Then
body = envelope.Get("Body")
Else
ParseError = True
ParseErrorMsg = "Soap Body Missing"
Return
End If
'
' extract Environment from Response
'
Dim MenuResponse As Map
If body.Get("ReturnMenuResponse") Is Map Then
MenuResponse = body.Get("ReturnMenuResponse")
Else
ParseError = True
ParseErrorMsg = "Menu Response is missing from Soap Envelope"
Return
End If
'
' extract environment from response
'
Dim MenuTransaction As Map
If MenuResponse.Get("MenuTransaction") Is Map Then
MenuTransaction = MenuResponse.Get("MenuTransaction")
Else
ParseError = True
ParseErrorMsg = "MenuTransaction is missing from Menu Response"
Return
End If
'Log(MenuTransaction)
'
' Extract Individual Attributes
'
'ClientBuild = Environment.Get("ClientBuild")
MenuID = MenuTransaction.Get("MenuID")
ErrorFlag = MenuTransaction.Get("ErrorFlag")
ErrorMessage = MenuTransaction.Get("ErrorMessage")
MenuJSON = MenuTransaction.Get("MenuDSJson")
'Log(MenuJSON)
Dim parser As JSONParser
parser.Initialize(MenuJSON)
Dim root As Map = parser.NextObject
MenuDetail = root.Get("MenuDetail")
MenuHeader = root.Get("MenuHeader")
End Sub
Sample using the class
Sub LoadMenu(MenuID As String)
Dim MenuTxn As clsMenuTransaction
MenuTxn.Initialize
MenuTxn.MenuID = MenuID
Dim j As HttpJob
j.Initialize("",Me)
j.PostString(Globals.WebServerPath & "server.asmx", MenuTxn.RequestXML )
j.GetRequest.SetContentType("text/xml; charset=utf-8")
j.GetRequest.SetHeader("SOAPAction",$""http://tempuri.org/ReturnMenu""$)
wait for (j) jobdone(j As HttpJob)
If j.Success Then
MenuTxn.ParseXml(j.GetString)
If MenuTxn.ParseError Then
Msgbox("Parse Error: " & MenuTxn.ParseErrorMsg,"Login Error")
j.Release
Return
End If
Else
Msgbox("Error Communicating with Web Server: " & j.ErrorMessage,"Login Error")
j.Release
Return
End If
j.Release
For Each colMenuHeader As Map In MenuTxn.MenuHeader
lblMenu.Text = "Menu: " & colMenuHeader.Get("MenuTitle")
Next
For Each colMenuDetail As Map In MenuTxn.MenuDetail
lvMenu.AddTextItem(colMenuDetail.Get("DisplayText"),colMenuDetail.Get("Reference"))
Next
End Sub
The .NET class
Public Class MenuTransaction
Inherits cError
Private iMenuID As String
Private iMenuDS As DataSet
Public MenuID As String
Public MenuDataSet As DataSet
Public MenuDSJson As String
End Class
The .NET method that creates the response:
Public Sub gReturnMenu(ByRef MenuTransaction As GlobalClassLib.GlobalClassLib.MenuTransaction)
With MenuTransaction
Dim SqlString As String = "SELECT * FROM MenuMaster_Header WHERE MenuID = '" & .MenuID & "'"
'
Dim TempDS As DataSet = WMSReturnDataset(SqlString, .ErrorFlag, .ErrorMessage)
If .ErrorFlag Then GoTo ExitSub
If TempDS.Tables(0).Rows.Count = 0 Then
.ErrorFlag = True
.ErrorMessage = "Invalid Menu " & .MenuID
If .ErrorFlag Then GoTo ExitSub
End If
Dim ActiveFlag As Boolean = TempDS.Tables(0).Rows(0).Item("ActiveFlag")
If Not (ActiveFlag) Then
.ErrorFlag = True
.ErrorMessage = "RM-1000: Menu is not enabled"
If .ErrorFlag Then GoTo ExitSub
End If
TempDS.Tables(0).TableName = "MenuHeader"
.MenuDataSet = TempDS
' .MenuDataSet.Tables.Add(TempDS.Tables(0).Copy)
Dim x As String = TempDS.Tables(0).TableName
SqlString = "SELECT * FROM MenuMaster_Items WHERE MenuID = '" & .MenuID & "' AND Enabled = 1 ORDER BY SortOrder"
TempDS = NovoReturnDataset(SqlString, .ErrorFlag, .ErrorMessage)
If .ErrorFlag Then GoTo ExitSub
If TempDS.Tables(0).Rows.Count = 0 Then
.ErrorFlag = True
.ErrorMessage = .MenuID & " contains no menu items."
If .ErrorFlag Then GoTo ExitSub
End If
TempDS.Tables(0).TableName = "MenuDetail"
.MenuDataSet.Tables.Add(TempDS.Tables(0).Copy)
.MenuDSJson = JsonConvert.SerializeObject(.MenuDataSet, Formatting.Indented)
End With
ExitSub:
End Sub
Hope this helps some folks...