BC365 - Error calling Web Service

isabtogumon
Member Posts: 50
Hello,
I have the following code and it throws an error when run, any suggestions that might help resolve the error?
Thanks in advance
Error: NavHttpClient Request Failed
Code:
codeunit 50401 ImportXMLMessage
{
procedure ImportXMLMessage()
var
SOAPAction: Record SOAPAction;
OutStrm: OutStream;
InStrm: InStream;
DialogTitle: Label 'Upload file...';
TempFileName: Text;
RequestHeaders: HttpHeaders;
RequestMessage: HttpRequestMessage;
RequestContent: HttpContent;
Client: HttpClient;
ResponseMessage: HttpResponseMessage;
Content: HttpContent;
XML: Text;
begin
Clear(SOAPAction.XMLMessage);
if not SOAPAction.XMLMessage.HasValue then begin
file.UploadIntoStream(DialogTitle, '', 'XML file(*.xml)|*.xml', TempFileName, InStrm);//then begin
Content.Clear();
RequestContent.Clear();
RequestHeaders.Clear();
RequestMessage.Content().Clear();
ResponseMessage.Content().Clear();
ResponseMessage.Headers().Clear();
RequestContent.WriteFrom(InStrm);
RequestContent.GetHeaders(RequestHeaders);
RequestHeaders.Remove('Content-Type');
RequestHeaders.Add('Content-Type', 'text/xml;charset=utf-8');
RequestHeaders.Add('SOAPAction', 'GetMovimentacao');
RequestMessage.Content := RequestContent;
RequestMessage.Method := 'POST';
RequestMessage.SetRequestUri('https://uhc.unihealth.com.br:3132/Interface.asmx');
RequestMessage.Content(RequestContent);
if Client.Send(RequestMessage, ResponseMessage) then begin
ResponseMessage.Content().ReadAs(XML);
Message(XML);
end else begin
Error('Error:\' +
'Status Code : %1\' +
'Description: %2',
ResponseMessage.HttpStatusCode,
ResponseMessage.ReasonPhrase);
end;
end;
}
I have the following code and it throws an error when run, any suggestions that might help resolve the error?
Thanks in advance
Error: NavHttpClient Request Failed
Code:
codeunit 50401 ImportXMLMessage
{
procedure ImportXMLMessage()
var
SOAPAction: Record SOAPAction;
OutStrm: OutStream;
InStrm: InStream;
DialogTitle: Label 'Upload file...';
TempFileName: Text;
RequestHeaders: HttpHeaders;
RequestMessage: HttpRequestMessage;
RequestContent: HttpContent;
Client: HttpClient;
ResponseMessage: HttpResponseMessage;
Content: HttpContent;
XML: Text;
begin
Clear(SOAPAction.XMLMessage);
if not SOAPAction.XMLMessage.HasValue then begin
file.UploadIntoStream(DialogTitle, '', 'XML file(*.xml)|*.xml', TempFileName, InStrm);//then begin
Content.Clear();
RequestContent.Clear();
RequestHeaders.Clear();
RequestMessage.Content().Clear();
ResponseMessage.Content().Clear();
ResponseMessage.Headers().Clear();
RequestContent.WriteFrom(InStrm);
RequestContent.GetHeaders(RequestHeaders);
RequestHeaders.Remove('Content-Type');
RequestHeaders.Add('Content-Type', 'text/xml;charset=utf-8');
RequestHeaders.Add('SOAPAction', 'GetMovimentacao');
RequestMessage.Content := RequestContent;
RequestMessage.Method := 'POST';
RequestMessage.SetRequestUri('https://uhc.unihealth.com.br:3132/Interface.asmx');
RequestMessage.Content(RequestContent);
if Client.Send(RequestMessage, ResponseMessage) then begin
ResponseMessage.Content().ReadAs(XML);
Message(XML);
end else begin
Error('Error:\' +
'Status Code : %1\' +
'Description: %2',
ResponseMessage.HttpStatusCode,
ResponseMessage.ReasonPhrase);
end;
end;
}
0
Answers
-
Hello @isabtogumon,
I use this procedure to call several SOAP WS and get back an XML documetnt with the response, you could try it and let me know if it works for you.local procedure CallPostWS(InS: InStream; URL: Text; SOAPAction: Text; var ErrorMsg: Text; var xmlDoc: XmlDocument): Boolean var Client: HttpClient; RequestContent: HttpContent; RequestHeader: HttpHeaders; RequestMsg: HttpRequestMessage; ResponseMSg: HttpResponseMessage; ResTxt: Text; begin // Add content RequestContent.WriteFrom(InS); // Add headers RequestHeader.Clear(); RequestContent.GetHeaders(RequestHeader); RequestHeader.Remove('Content-Type'); RequestHeader.Add('Content-Type', 'text/xml; charset=UTF-8'); if SOAPAction <> '' then RequestHeader.Add('SOAPAction', SOAPAction); RequestMsg.Content(RequestContent); // Set URL and Method RequestMsg.SetRequestUri(URL); RequestMsg.Method('POST'); if Client.Send(RequestMsg, ResponseMSg) then begin if ResponseMSg.IsSuccessStatusCode() then begin ResponseMSg.Content.ReadAs(ResTxt); if XmlDocument.ReadFrom(ResTxt, XMLDoc) then begin ErrorMsg := ''; exit(true); end else begin ErrorMsg := ResTxt; exit(false); end; end else begin ErrorMsg := ResponseMSg.ReasonPhrase(); exit(false); end; end else begin if ResponseMSg.Content.ReadAs(ResTxt) then ErrorMsg := ResTxt; exit(false); end; end;
Regards0 -
Hello @ftornero and thanks,
I tried with the suggested code, honestly I didn't make a lot of modifications as it is similar to mine, but it still has the same error. I'm not sure if it is presented by URL or procedure. Is it possible that you can share some code that works with real URLs so that I can see the procedure?0 -
Hello @isabtogumon,
You can use this site to test the SOAP WS call.
https://www.crcind.com/csp/samples/SOAP.Demo.CLS
Regards0 -
Hello @ftornero and thanks again
I must be doing something wrong since even with the test site it sends me the same error. I used the procedure below
procedure LoadXMLandCallWS()
var
InStr: InStream;
DialogTitle: Label 'Subir archivo...';
TempFileName: Text;
RequestHeaders: HttpHeaders;
RequestMessage: HttpRequestMessage;
RequestContent: HttpContent;
Client: HttpClient;
ResponseMessage: HttpResponseMessage;
XML: Text;
begin
file.UploadIntoStream(DialogTitle, '', 'XML file(*.xml)|*.xml', TempFileName, InStr);
RequestContent.WriteFrom(InStr);
RequestHeaders.Clear();
RequestContent.GetHeaders(RequestHeaders);
RequestHeaders.Remove('Content-Type');
RequestHeaders.Add('Content-Type', 'text/xml; charset=UTF-8');
RequestHeaders.Add('SOAPAction', 'FindPerson');
RequestMessage.SetRequestUri('https://www.crcind.com/csp/samples/SOAP.Demo.CLS');
RequestMessage.Method('POST');
if Client.Send(RequestMessage, ResponseMessage) then begin
ResponseMessage.Content().ReadAs(XML);
Message(XML);
end else begin
Error('Error: \' +
'Status Code: %1\' +
'Description: %2',
ResponseMessage.HttpStatusCode,
ResponseMessage.ReasonPhrase);
end;
end;
}
Below is stored in InStream
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:s="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Body>
<FindPersonResponse xmlns="http://tempuri.org"/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>0 -
Hello @isabtogumon
I have added this line to you code, marked with "// <<
This line is missing"
RequestMessage.Content(RequestContent);procedure LoadXMLandCallWS() var InStr: InStream; DialogTitle: Label 'Subir archivo...'; TempFileName: Text; RequestHeaders: HttpHeaders; RequestMessage: HttpRequestMessage; RequestContent: HttpContent; Client: HttpClient; ResponseMessage: HttpResponseMessage; XML: Text; begin file.UploadIntoStream(DialogTitle, '', 'XML file(*.xml)|*.xml', TempFileName, InStr); RequestContent.WriteFrom(InStr); RequestHeaders.Clear(); RequestContent.GetHeaders(RequestHeaders); RequestHeaders.Remove('Content-Type'); RequestHeaders.Add('Content-Type', 'text/xml; charset=UTF-8'); RequestHeaders.Add('SOAPAction', 'FindPerson'); RequestMessage.SetRequestUri('https://www.crcind.com/csp/samples/SOAP.Demo.CLS'); RequestMessage.Content(RequestContent); // <<------ This line is missing RequestMessage.Method('POST'); if Client.Send(RequestMessage, ResponseMessage) then begin ResponseMessage.Content().ReadAs(XML); Message(XML); end else begin Error('Error: \' + 'Status Code: %1\' + 'Description: %2', ResponseMessage.HttpStatusCode, ResponseMessage.ReasonPhrase); end; end;
The input XML is this one:<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org"> <soapenv:Header/> <soapenv:Body> <tem:FindPerson> <tem:id>1</tem:id> </tem:FindPerson> </soapenv:Body> </soapenv:Envelope>
And i got this response:
Regards
0 -
Hello @ftornero
Thanks for your reply, that fixes the problem. However, I still have not managed to make it work in the URL I want, I do not know if it is because in the content of the XML it has lines with username and password, and that in turn must be defined in the header. The content of the XML is this.<?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> <GetMovimentacao xmlns="http://www.unihealth.com.br/Unihealth"> <Credencial> <UserName>Username</UserName> <Password>Password</Password> </Credencial> </GetMovimentacao> </soap:Body> </soap:Envelope>
If the content of the XML has credentials, is it necessary to add something else to the structure of the procedure?0 -
Hello @isabtogumon,
That depends of the WS that you are calling.
Don't you have any documentation about the WS, the WS description , a WSDL file, etc. ?
Regards0 -
Hi @ftornero
I did a test in Postman and if it gave me an answer, I looked into the code options and noticed that there is a line that adds the host, I tried to add it in the structure of the AL code, however it sends an error.
These are the lines I tried to add:RequestHeaders.Remove('Host'); RequestHeaders.Add('Host', 'uhc.unihealth.com.br');
This is the error that Business Central sends:
Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects.
Do you know how to add the host to the header or how should I add the host?0 -
Hello @isabtogumon,
I don't think that header is necessary because usually is provided for the Http client and get from the URL
The answer that you get from Postman is the expected one ?
Regards0 -
0
-
Hello @isabtogumon,
Could you post the data with the Postman call, hiding the sensitive information ?
Regards0 -
0
-
Hello @isabtogumon,,
Well, the XML is pretty simple and that must works from BC without any issue.
If you want, we could connect and I take a look at your code.
Regards0 -
Thanks @ftornero
If you have the opportunity to connect, I would appreciate it. Please tell me what time is convenient for you and through which tool0 -
0
-
Hello @isabtogumon,
I don't know if you have solve the conection problem with de remote WS.
Here is some informatio about the IP range en BC SaaS
https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/faq#which-ip-addresses-or-ranges-does-my-environments-api-use
and a post about the same problem wuth the IP white list the some WS.
https://community.dynamics.com/business/f/dynamics-365-business-central-forum/276553/can-we-set-up-a-static-ip-address-to-dynamics-365-business-central-on-cloud
And a little App to show the client IP address:page 50149 "GetIP Page" { Caption = 'Get IP'; layout { } actions { area(Processing) { action(GetIP) { Promoted = true; PromotedIsBig = true; PromotedOnly = true; Image = Line; ApplicationArea = All; PromotedCategory = Process; Caption = 'Show IP'; trigger OnAction() begin Message('IP Address: %1', GetIPAddress()); end; } } } local procedure GetIPAddress(): Text var CodError: Text; ResTxt: Text; begin if CallWSRESTApi('https://naturlider2.azurewebsites.net/api/GetIP?code=WyvxPLBnJYjCqebJyFm7UYoyQAT15Zu5MOR/9AfDZQElBYCzPqtd5w==', 'GET', '', '', '', CodError, ResTxt) then exit(ResTxt) else Exit('IP unknown'); end; local procedure CallWSRESTApi(apiUrl: text; method: text; contentType: Text; contentText: Text; apiKey: Text; var CodigoError: Text; var ResTxt: Text): Boolean var Client: HttpClient; Content: HttpContent; RequestMsg: HttpRequestMessage; RequestHeader: HttpHeaders; ContentHeader: HttpHeaders; ResponseMSg: HttpResponseMessage; begin if method <> 'GET' then begin // Write content Content.Clear(); if StrLen(contentText) > 0 then Content.WriteFrom(contentText); ContentHeader.Clear(); Content.GetHeaders(ContentHeader); ContentHeader.Remove('Content-Type'); if contentType <> '' then ContentHeader.Add('Content-Type', contentType) else ContentHeader.Add('Content-Type', 'application/json'); RequestMsg.Content(Content); end; RequestHeader.Clear(); RequestMsg.GetHeaders(RequestHeader); RequestMsg.SetRequestUri(apiUrl); RequestMsg.Method(method); if Client.Send(RequestMsg, ResponseMSg) then begin if ResponseMSg.IsSuccessStatusCode() then begin ResponseMSg.Content.ReadAs(ResTxt); CodigoError := ''; exit(true); end else begin CodigoError := Format(ResponseMSg.HttpStatusCode()) + ' ' + ResponseMSg.ReasonPhrase(); ResponseMSg.Content.ReadAs(ResTxt); if ResTxt = '' then ResTxt := CodigoError; if (method = 'DELETE') and (ResponseMSg.HttpStatusCode = 404) then exit(true) else exit(false); end; end else begin CodigoError := 'ERROR'; if ResponseMSg.Content.ReadAs(ResTxt) then; if ResTxt = '' then ResTxt := CodigoError; exit(false); end; end; }
Regards0 -
Hello @ftornero
I have already confirmed the reason for the error, this is due to the restriction of the server where the web service is hosted. I tried the code in the locale and it worked fine there, I got the expected result. Regarding access for cloud environment, IP range will be whitelist, I hope that will solve the problem.
I did test the code to get the IP address, but from what I read in the link, BC's IP is dynamic so if it is whitelist the IP might change and an error would occur.
0
Categories
- All Categories
- 73 General
- 73 Announcements
- 66.6K Microsoft Dynamics NAV
- 18.7K NAV Three Tier
- 38.4K NAV/Navision Classic Client
- 3.6K Navision Attain
- 2.4K Navision Financials
- 116 Navision DOS
- 851 Navision e-Commerce
- 1K NAV Tips & Tricks
- 772 NAV Dutch speaking only
- 617 NAV Courses, Exams & Certification
- 2K Microsoft Dynamics-Other
- 1.5K Dynamics AX
- 320 Dynamics CRM
- 111 Dynamics GP
- 10 Dynamics SL
- 1.5K Other
- 990 SQL General
- 383 SQL Performance
- 34 SQL Tips & Tricks
- 35 Design Patterns (General & Best Practices)
- 1 Architectural Patterns
- 10 Design Patterns
- 5 Implementation Patterns
- 53 3rd Party Products, Services & Events
- 1.6K General
- 1.1K General Chat
- 1.6K Website
- 83 Testing
- 1.2K Download section
- 23 How Tos section
- 252 Feedback
- 12 NAV TechDays 2013 Sessions
- 13 NAV TechDays 2012 Sessions