Consume external NAV SOAP webservices from SaaS BC

weneedweneed Member Posts: 80
I am trying to consume a webservices in Business Central 14 (RTC C/AL) from Business central (BC19).
I need to send an xml file from BC19 to BC14 to obtain checks and validation.
So, I've a function in CU to do this:
[External] ValidaXML_AIFM(VAR _XMLToValidate : Text;VAR _Error : Text) RetVal : Boolean

IF NOT TryValidate(XMLDoc) THEN BEGIN
  RetVal := FALSE;
  _Error := GETLASTERRORTEXT;
END ELSE
  RetVal := TRUE;
and this is sample
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
    <Body>
        <ValidaXML_AIFM xmlns="urn:microsoft-dynamics-schemas/codeunit/AIFMValidation">
            <_XMLToValidate>[string]</_XMLToValidate>
            <_Error>[string]</_Error>
        </ValidaXML_AIFM>
    </Body>
</Envelope>
In BC19 executing an action user send xml file.
This is code (from here):
trigger OnAction()
                var
                    FileMgnt_: Codeunit "File Management";
                    TempBlob_: Codeunit "Temp Blob";
                    InStream_: InStream;
                    Text50000_: Label 'Select file';
                    FileFilterTxt_: Label 'XML File (*.xml)|*.xml';
                    ExtFilterTxt_: Label 'xml';
                    Client_: HttpClient;
                    Content_: HttpContent;
                    Request_: HttpRequestMessage;
                    RequestHdr_: httpheaders;
                    ContentHdr_: HttpHeaders;
                    ResponseMSg_: HttpResponseMessage;
                    Response_: HttpResponseMessage;
                    CnvTo64_: codeunit "Base64 Convert";
                    Parameters_: XmlDocument;
                    Url: Text;
                    AuthText_: text;
                    ResTxt_: Text;
                    XML_String: Text;
                    ErrorCode_: Text;
                begin
                    Url := 'http://myserver.domain:7257/NAV_WS/WS/CRONUS%20Italia%20S.p.A./Codeunit/AIFMValidation';
                    RequestHdr_.Clear();
                    AuthText_ := CnvTo64_.ToBase64('MyUsername:MyPassword');
                    Request_.GetHeaders(RequestHdr_);
                    RequestHdr_.Add('Accept', 'application/xml');
                    RequestHdr_.Add('Authorization', StrSubstNo('NTLM %1', AuthText_));

                    ContentHdr_.Clear();
                    Content_.GetHeaders(ContentHdr_);
                    ContentHdr_.Remove('Content-Type');
                    ContentHdr_.Add('Content-Type', 'text/xml');
                    Request_.Content(Content_);

                    FileMgnt_.BLOBImportWithFilter(TempBlob_, Text50000_, '', FileFilterTxt_, ExtFilterTxt_);
                    TempBlob_.CreateInStream(InStream_, TextEncoding::UTF8);
                    instream_.ReadText(XML_String);                    
                    Content_.writefrom(XML_String);                    

                    Request_.SetRequestUri(Url);
                    Request_.method('POST');
                    if Client_.Send(Request_, Response_) then begin
                        if Response_.IsSuccessStatusCode() then begin
                            Response_.Content.ReadAs(ResTxt_);
                            if XmlDocument.ReadFrom(ResTxt_, XMLDoc2_) then begin
                                ErrorCode_ := '';
                            end else begin
                                ErrorCode_ := ResTxt_;
                                Message(ErrorCode_);
                            end
                        end else begin
                            ErrorCode_ := Response_.ReasonPhrase();
                            error(ErrorCode_);
                        end;

                    end else begin
                        if Response_.Content.ReadAs(ResTxt_) then begin
                            ErrorCode_ := ResTxt_;
                            Error(ErrorCode_);
                        end else begin
                            ErrorCode_ := Response_.ReasonPhrase;
                            Message(ErrorCode_);
                        end
                    end;
                end;
Unfortunately, executing code returns BADREQUEST error.
Where am I wrong?

Comments

  • ftorneroftornero Member Posts: 522
    Hello @weneed

    In BC14, for the user, you need to activate the Web Service Access, and use Basic authentication with the user name and the Web Service Key.

    g1hd8cqdw4z9.png

    Regardd
  • weneedweneed Member Posts: 80
    Hi @ftornero problem is not authentication I think.
  • ftorneroftornero Member Posts: 522
    edited 2022-09-14
    Hello @weneed,

    If the authentication works for you then ok , in the other hand change this code
                        ContentHdr_.Clear();
                        Content_.GetHeaders(ContentHdr_);
                        ContentHdr_.Remove('Content-Type');
                        ContentHdr_.Add('Content-Type', 'text/xml');
                        Request_.Content(Content_);
    
                        FileMgnt_.BLOBImportWithFilter(TempBlob_, Text50000_, '', FileFilterTxt_, ExtFilterTxt_);
                        TempBlob_.CreateInStream(InStream_, TextEncoding::UTF8);
                        instream_.ReadText(XML_String);                    
                        Content_.writefrom(XML_String);  
    

    Like that
                        ContentHdr_.Clear();
                        Content_.GetHeaders(ContentHdr_);
                        ContentHdr_.Remove('Content-Type');
                        ContentHdr_.Add('Content-Type', 'text/xml');
    
                        RequestHdr_.Add('SOAPAction', 'ValidaXML_AIFM');
    
                        FileMgnt_.BLOBImportWithFilter(TempBlob_, Text50000_, '', FileFilterTxt_, ExtFilterTxt_);
                        TempBlob_.CreateInStream(InStream_, TextEncoding::UTF8);
                        Content_.Writefrom(InStream);  
                        Request_.Content(Content_);
    

    Regards
  • weneedweneed Member Posts: 80
    Hello, unfortunately it still gives me the same error: Badrequest ..
  • ftorneroftornero Member Posts: 522
    Hello @weneed,

    Have you try to use Postman to see if the problem is with BC19 or with BC14 ?
  • weneedweneed Member Posts: 80
    Yes Postman work.
    I had to set in the header:
    SOAPAction urn:microsoft-dynamics-schemas/codeunit/AIFMValidationValidaXML_AIFM
    

    and in the body:
    <Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
        <Body>
            <ValidaXML_AIFM xmlns="urn:microsoft-dynamics-schemas/codeunit/AIFMValidation">
                <_XMLToValidate></_XMLToValidate>
                <_Error></_Error>
            </ValidaXML_AIFM>
        </Body>
    </Envelope>
    

    I miss to fill _XMLToValidate parameter to check.
    Works
  • ftorneroftornero Member Posts: 522
    Hello @weneed,

    I tested it and your code with the modifications I said works,

    Are you sure that the SOAPAction in Postman ended with AIFMValidationValidaXML_AIFM ?

    Could you post again your code with the modifications ?

    Regards.
  • weneedweneed Member Posts: 80
    edited 2022-09-15
    HI @ftornero,

    this is my code now:
    trigger OnAction()
                    var
                        FileMgnt_: Codeunit "File Management";
                        TempBlob_: Codeunit "Temp Blob";
                        InStream_: InStream;
                        Text50000_: Label 'Selezionare il file da validare';
                        FileFilterTxt_: Label 'XML File (*.xml)|*.xml';
                        ExtFilterTxt_: Label 'xml';
                        Client_: HttpClient;
                        Content_: HttpContent;
                        Request_: HttpRequestMessage;
                        RequestHdr_: httpheaders;
                        ContentHdr_: HttpHeaders;
                        ResponseMSg_: HttpResponseMessage;
                        Response_: HttpResponseMessage;
                        CnvTo64_: codeunit "Base64 Convert";
                        Parameters_: XmlDocument;
                        Url: Text;
                        AuthText_: text;
                        ResTxt_: Text;
                        XML_String: Text;
                        XMLDoc2_: XmlDocument;
                        ErrorCode_: Text;
                    begin
                        Url := 'http://myserver.domain:7257/NAV_WS/WS/CRONUS%20Italia%20S.p.A./Codeunit/AIFMValidation';
                        RequestHdr_.Clear();
                        AuthText_ := CnvTo64_.ToBase64('MyUser:MyPassword');
                        Request_.GetHeaders(RequestHdr_);
                        RequestHdr_.Add('Accept', 'application/xml');
                        RequestHdr_.Add('Authorization', StrSubstNo('NTLM %1', AuthText_));
                        RequestHdr_.Add('SOAPAction', 'urn:microsoft-dynamics-schemas/codeunit/AIFMValidationValidaXML_AIFM');
    
                        ContentHdr_.Clear();
                        Content_.GetHeaders(ContentHdr_);
                        ContentHdr_.Remove('Content-Type');
                        ContentHdr_.Add('Content-Type', 'text/xml');
    
                        FileMgnt_.BLOBImportWithFilter(TempBlob_, Text50000_, '', FileFilterTxt_, ExtFilterTxt_);
                        TempBlob_.CreateInStream(InStream_, TextEncoding::UTF8);
                        Content_.Writefrom(InStream_);  
                        Request_.Content(Content_);
    
                        Request_.SetRequestUri(Url);
                        Request_.method('POST');
                        if Client_.Send(Request_, Response_) then begin
                            if Response_.IsSuccessStatusCode() then begin
                                Response_.Content.ReadAs(ResTxt_);
                                if XmlDocument.ReadFrom(ResTxt_, XMLDoc2_) then begin
                                    ErrorCode_ := '';
                                end else begin
                                    ErrorCode_ := ResTxt_;
                                    Message(ErrorCode_);
                                end
                            end else begin
                                ErrorCode_ := Response_.ReasonPhrase();
                                error(ErrorCode_);
                            end;
    
                        end else begin
                            if Response_.Content.ReadAs(ResTxt_) then begin
                                ErrorCode_ := ResTxt_;
                                Error(ErrorCode_);
                            end else begin
                                ErrorCode_ := Response_.ReasonPhrase;
                                Message(ErrorCode_);
                            end
                        end;
                    end;
    

    result of the call is:
    o7j4nu3od8au.png
    The result is the same in both cases:
    RequestHdr_.Add('SOAPAction', 'urn:microsoft-dynamics-schemas/codeunit/AIFMValidationValidaXML_AIFM');
    
    RequestHdr_.Add('SOAPAction', 'urn:microsoft-dynamics-schemas/codeunit/AIFMValidation');
    
    What I am asking is how to indicate to the ws that we want to use one method rather than another?

    I think the request is incorrect. It should look like this:
    <Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
        <Body>
            <ValidaXML_AIFM xmlns="urn:microsoft-dynamics-schemas/codeunit/AIFMValidation">
                <_XMLToValidate>[string]</_XMLToValidate>
                <_Error>[string]</_Error>
            </ValidaXML_AIFM>
        </Body>
    </Envelope>
    
  • ftorneroftornero Member Posts: 522
    Hello @weneed,

    The SOAPAction should be only the name of the procedure that you are calling
                        RequestHdr_.Add('SOAPAction', 'ValidaXML_AIFM');
    

    And regarding the request, is an XML that you provided in this line
                  FileMgnt_.BLOBImportWithFilter(TempBlob_, Text50000_, '', FileFilterTxt_, ExtFilterTxt_);
    

    So get a correct XML file.

    Regards.
  • weneedweneed Member Posts: 80
    But here
    FileMgnt_.BLOBImportWithFilter(TempBlob_, Text50000_, '', FileFilterTxt_, ExtFilterTxt_);
    I'm reading XML File that is the first parameter:
    <_XMLToValidate></_XMLToValidate>
    

  • ftorneroftornero Member Posts: 522
    Hello @weneed,

    Ok, that's the problem, you need to wrap this XML inside that tag, something like this:
    <Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
    <Body>
      <m:ValidaXMLAIFM xmlns:m="urn:microsoft-dynamics-schemas/codeunit/WSBC14">
        <m:_XMLToValidate>
          <![CDATA[ <SH> <SHTime> <SHTimeFrom>2018-07-24T00:00:00</SHTimeFrom> 
          <SHTimeTo>2018-07-25T14:19:11</SHTimeTo> </SHTime> <SHresults> <SHresult id="267063362374320"> <SHrevsecno>06G8M</SHrevsecno> <SHownersecno>06G8M</SHownersecno> <SHrevlogin>EXT0011</SHrevlogin> <SHrevdiv>RPS TESTING PARAMETERS</SHrevdiv> <SHstatus>DS New</SHstatus> <SHrevdate>07-24-2018 17:39:06</SHrevdate> <SHname></SHname> <SHcompany>Winston</SHcompany> <SHoptid></SHoptid> </SHresult> </SHresults> </SH> ]]>
          </m:_XMLToValidate>
          <m:_Error/>
        </m:ValidaXMLAIFM>
      </Body>
    </Envelope>
    

    And this new XML is the one to put in the Content.
  • weneedweneed Member Posts: 80
    Hi, this is content that I've write in th XML:
    <Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
        <Body>
            <ValidaXML_AIFM xmlns="urn:microsoft-dynamics-schemas/codeunit/AIFMValidation">
                <_XMLToValidate>Test</_XMLToValidate>
                <_Error></_Error>
            </ValidaXML_AIFM>
        </Body>
    </Envelope>
    
    but not work. Return always Bar request
  • ftorneroftornero Member Posts: 522
    edited 2022-09-15
    Hello @weneed

    Use this one:
    <Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
        <Body>
            <m:ValidaXML_AIFM xmlns:m="urn:microsoft-dynamics-schemas/codeunit/AIFMValidation">
                <m:_XMLToValidate>Test</m:_XMLToValidate>
                <m:_Error></m:_Error>
            </m:ValidaXML_AIFM>
        </Body>
    </Envelope>
    
  • weneedweneed Member Posts: 80
    Not work. Same error..
  • ftorneroftornero Member Posts: 522
    Hello @weneed ,

    Could you post the line with the SOAPAction ?

    Regards
  • weneedweneed Member Posts: 80
    RequestHdr_.Add('SOAPAction', 'ValidaXML_AIFM');
  • ftorneroftornero Member Posts: 522
    Hello @weneed,

    Well, the code, in my case with Basic Authentication, works with the tests that I have done.

    Sorry, without see your environment, I'm out of ideas.

    Regards
  • weneedweneed Member Posts: 80
    Hi @ftornero,
    To understand the problem I'm trying to intercept the call with fiddler but I can't.
    Every time I try fiddler it doesn't record anything ..
    Fiddler is installed on the same server on which the BC service is.
    Why?? If I use postman instead, it detects the call.
    I also doing a different test: in a new project with target 'onPrem' I use the CU "SOAP Web Service Request Mgt." Also in this case it does not work.
    This is code:
    var
                        SOAP: Codeunit "SOAP Web Service Request Mgt.";
                        url: Text;
                        prova: Text;
                        InStream_: InStream;
                        OutStrem_: OutStream;
                        TempBlob_: Codeunit "Temp Blob";
                        FileMgnt_: Codeunit "File Management";
                        Text50000_: Label 'Selezionare il file da validare';
                        FileFilterTxt_: Label 'XML File (*.xml)|*.xml';
                        ExtFilterTxt_: Label 'xml';
                        RespInStream: InStream;
                    begin
                        url := 'http://myserver.domain.local:7457/NAV_WS/WS/CRONUS%20Italia%20S.p.A./Codeunit/AIFMValidation';
                        FileMgnt_.BLOBImportWithFilter(TempBlob_, Text50000_, '', FileFilterTxt_, ExtFilterTxt_);
                        TempBlob_.CreateInStream(InStream_, TextEncoding::UTF8);                    
    
                        SOAP.SetGlobals(InStream_, url, '', '');
                        SOAP.SetTraceMode(true);
                        SOAP.DisableHttpsCheck();
                        SOAP.SetAction('VALIDAXML_AIFM');
                        SOAP.SetContentType('text/xml');
    
                        SOAP.SendRequestToWebService();                  
    
                        Message('Done');
                    end;
    
    BlobImportWithFilter read this xml file that put in request:
    <Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
        <Body>
            <ValidaXML_AIFM xmlns="urn:microsoft-dynamics-schemas/codeunit/AIFMValidation">
                <_XMLToValidate>Test</_XMLToValidate>
                <_Error></_Error>
            </ValidaXML_AIFM>
        </Body>
    </Envelope>
    
    but server returns
    eewnhbflc5gr.png

    Again fiddler does not record the call
  • ftorneroftornero Member Posts: 522
    Hello @weneed,

    Like I said before in the tests that I did it works, so without taking a look to your scenario I can help you.

    Regards.
Sign In or Register to comment.