Up to now we in Advania have been using the method described here on my blog to connect to most of the Soap web services that we needed to integrate with.
The problem with this method is that we have to manage a lot of DLLs. This has caused some issues and problems.
Another thing is that we are moving to AL. And in AL we can’t just throw in a custom DLL to do all the work.
In C/AL We can do this with standard dotnet objects
DOMDoc := DOMDoc.XmlDocument; DOMProcessingInstruction := DOMDoc.CreateProcessingInstruction('xml','version="1.0" encoding="utf-8"'); DOMDoc.AppendChild(DOMProcessingInstruction); DOMElement := DOMDoc.CreateElement('soap:Envelope','http://schemas.xmlsoap.org/soap/envelope/'); DOMElement.SetAttribute('xmlns:soap','http://schemas.xmlsoap.org/soap/envelope/'); DOMElement.SetAttribute('xmlns:xsi','http://www.w3.org/2001/XMLSchema-instance'); DOMElement.SetAttribute('xmlns:xsd','http://www.w3.org/2001/XMLSchema'); DOMElement.SetAttribute('xmlns:ws','http://ws.msggw.siminn'); DOMElement2 := DOMDoc.CreateElement('soap:Header','http://schemas.xmlsoap.org/soap/envelope/'); DOMElement.AppendChild(DOMElement2); DOMElement2 := DOMDoc.CreateElement('soap:Body','http://schemas.xmlsoap.org/soap/envelope/'); DOMElement3 := DOMDoc.CreateElement('ws:sendSMS','http://ws.msggw.siminn'); DOMElement4 := DOMDoc.CreateElement('ws:username','http://ws.msggw.siminn'); DOMElement4.InnerText := SMSSetup."Service User Name"; DOMElement3.AppendChild(DOMElement4); DOMElement4 := DOMDoc.CreateElement('ws:password','http://ws.msggw.siminn'); DOMElement4.InnerText := SMSSetup."Service Password"; DOMElement3.AppendChild(DOMElement4); DOMElement4 := DOMDoc.CreateElement('ws:source','http://ws.msggw.siminn'); DOMElement4.InnerText := SMSSetup.Sender; DOMElement3.AppendChild(DOMElement4); DOMElement4 := DOMDoc.CreateElement('ws:destination','http://ws.msggw.siminn'); DOMElement4.InnerText := SendTo; DOMElement3.AppendChild(DOMElement4); DOMElement4 := DOMDoc.CreateElement('ws:text','http://ws.msggw.siminn'); DOMElement4.InnerText := SendText; DOMElement3.AppendChild(DOMElement4); DOMElement4 := DOMDoc.CreateElement('ws:encoding','http://ws.msggw.siminn'); DOMElement4.InnerText := '0'; DOMElement3.AppendChild(DOMElement4); DOMElement4 := DOMDoc.CreateElement('ws:flash','http://ws.msggw.siminn'); DOMElement4.InnerText := '0'; DOMElement3.AppendChild(DOMElement4); DOMElement2.AppendChild(DOMElement3); DOMElement.AppendChild(DOMElement2); DOMDoc.AppendChild(DOMElement); HttpWebRequest := HttpWebRequest.Create(SMSSetup."SOAP URL"); HttpWebRequest.Timeout := 30000; HttpWebRequest.UseDefaultCredentials(TRUE); HttpWebRequest.Method := 'POST'; HttpWebRequest.ContentType := 'text/xml; charset=utf-8'; HttpWebRequest.Accept := 'text/xml'; HttpWebRequest.Headers.Add('soapAction','urn:sendSMS'); MemoryStream := HttpWebRequest.GetRequestStream; DOMDoc.Save(MemoryStream); MemoryStream.Flush; MemoryStream.Close; NAVWebRequest := NAVWebRequest.NAVWebRequest; IF NOT NAVWebRequest.doRequest(HttpWebRequest,HttpWebException,HttpWebResponse) THEN ERROR(Text003,HttpWebException.Status.ToString,HttpWebException.Message); MemoryStream := HttpWebResponse.GetResponseStream; DOMResponseDoc := DOMResponseDoc.XmlDocument; DOMResponseDoc.Load(MemoryStream); MemoryStream.Flush; MemoryStream.Close; ReceivedNameSpaceMgt := ReceivedNameSpaceMgt.XmlNamespaceManager(DOMResponseDoc.NameTable); ReceivedNameSpaceMgt.AddNamespace('ns','http://ws.msggw.siminn'); DOMNode := DOMResponseDoc.SelectSingleNode('//ns:return',ReceivedNameSpaceMgt); Response := DOMNode.InnerText; Success := Response = 'SUCCESS'; IF ShowResult AND Success THEN MESSAGE(Text001) ELSE IF ShowResult AND NOT Success THEN ERROR(Text005,Response);
AL code to do the same with the built in AL objects but that code is not much shorter.
With a custom proxy DLL the code would be
Proxy := Proxy.SMSWS; Proxy.Url := SMSSetup."SOAP URL"; Response := Proxy.sendSMS(Username,Password,SenderText,SendTo,SendText,'0',FALSE,FALSE,'0'); Success := Response = 'SUCCESS'; IF ShowResult AND Success THEN MESSAGE(Text001) ELSE IF ShowResult AND NOT Success THEN ERROR(Text005,Response);
With this example we can easily see why we have chosen to create a proxy DLL for most of the Soap services.
I wanted to find a way to make things easier in AL and I remembered having dealt with C/AL objects by Vjeko from some time ago. I took another look and that code helped me to get started.
The result is a Soap Proxy Client Mgt. Codeunit in C/AL that I have sent to Microsoft’s cal-open-library project asking to have this code put into the standard C/AL library.
Using this Codeunit the code will be like this.
WITH SoapProxyClientMgt DO BEGIN CreateSoapProxy(SMSSetup."SOAP URL"); InitParameters(9); SetParameterValue(Username,1); SetParameterValue(Password,2); SetParameterValue(SenderText,3); SetParameterValue(SendTo,4); SetParameterValue(SendText,5); SetParameterValue('0',6); SetParameterValue(FALSE,7); SetParameterValue(FALSE,8); SetParameterValue('0',9); InvokeMethod('SMSWS','sendSMS',TempBlob); XmlBuffer.LoadFromText(TempBlob.ReadAsTextWithCRLFLineSeparator); IF XmlBuffer.FindNodesByXPath(XmlBuffer,'/string') THEN Response := XmlBuffer.Value; Success := Response = 'SUCCESS'; IF ShowResult AND Success THEN MESSAGE(Text001) ELSE IF ShowResult AND NOT Success THEN ERROR(Text005,Response); END;
What about AL?
For now this C/AL Codeunit is not in the standard CRONUS database. I need to import the C/AL code and make sure that AL will be able to use that Codeunit. You can see how to do this in my last blog post.
This C/AL Code will directly convert to AL and is ready to use.
with SoapProxyClientMgt do begin CreateSoapProxy(SMSSetup."SOAP URL"); InitParameters(9); SetParameterValue(Username,1); SetParameterValue(Password,2); SetParameterValue(SenderText,3); SetParameterValue(SendTo,4); SetParameterValue(SendText,5); SetParameterValue('0',6); SetParameterValue(false,7); SetParameterValue(false,8); SetParameterValue('0',9); InvokeMethod('SMSWS','sendSMS',TempBlob); XmlBuffer.LoadFromText(TempBlob.ReadAsTextWithCRLFLineSeparator); if XmlBuffer.FindNodesByXPath(XmlBuffer,'/string') then Response := XmlBuffer.Value; Success := Response = 'SUCCESS'; if ShowResult and Success then MESSAGE(Text001) else if ShowResult and not Success then ERROR(Text005,Response); end;
More examples on how to use this Proxy Codeunit will follow. Stay tuned…