Solid experience about NAV 2013 Webservice for Page/Codeunit

roytseroytse Member Posts: 8
edited 2014-11-13 in NAV Three Tier
I am just here to share a bit of tips about how to call / consume the web service of Page/Codeunit in NAV 2013 by C/AL.
you can find many notes about how to make it in C/AL on Internet. However, in my object, i will let you know how to make it with SSL in different kind of authentication (Windows / NavUserPassword), and also let you know how to call method of Codeunit / Pages.

Please find the examples and detail remarks below. I haven't tidy-up the coding there, at least, I hope it would be the tips inspiring you to get another solution.

haha - example for Codeunit
hehehaha - exmaple for Page








OBJECT Codeunit 50000 haha
{
OBJECT-PROPERTIES
{
Date=28/03/13;
Time=11:38:23;
Modified=Yes;
Version List=;
}
PROPERTIES
{
OnRun=VAR
XmlHttp@1000000002 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 6.0:{88D969C6-F192-11D4-A65F-0040963251E5}:'Microsoft XML, v6.0'.ServerXMLHTTP40";
XmlDoc@1000000001 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 6.0:{F6D90F11-9C73-11D3-B32E-00C04F990BB4}:'Microsoft XML, v6.0'.DOMDocument";
XmlNode@1000000000 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 6.0:{2933BF80-7B36-11D2-B20E-00C04F983E60}:'Microsoft XML, v6.0'.IXMLDOMNode";
BEGIN
IF ISCLEAR(XmlDoc) THEN
CREATE(XmlDoc,FALSE,TRUE);
IF ISCLEAR(XmlHttp) THEN
CREATE(XmlHttp,FALSE,TRUE);

XmlHttp.open('POST','https://localhost:7047/DynamicsNAV70/WS/'+COMPANYNAME+'/Codeunit/'+ Text002,0);//,domain/windowslogin,PASSWORD);
XmlHttp.setRequestHeader('Content-Type', 'text/xml; charset=utf-8');
XmlHttp.setRequestHeader('SOAPAction',Text002);
XmlHttp.setOption(2,12800);


XmlHttp.setTimeouts(10000,10000,10000,0); //change last parameter to zero to wait till webservice finishes the job

XmlHttp.send('<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">' +
'<soap:Body><Hehe xmlns="urn:microsoft-dynamics-schemas/codeunit/'+ Text002 +'">' +
//'<soap:Body><hehe xmlns="https://localhost:7047/DynamicsNAV70/WS/'+COMPANYNAME+'/Codeunit/'+ Text002 +'">' +
'<userName>ROY</userName><password>hehe</password>'+
'</Hehe></soap:Body></soap:Envelope>');




IF XmlHttp.status <> 200 THEN
MESSAGE('Http Error ' + ' ' + FORMAT(XmlHttp.status) + ': ' + XmlHttp.statusText);

XmlDoc.async := FALSE;
XmlDoc.load(XmlHttp.responseBody);

XmlNode := XmlDoc.selectSingleNode('//Soap:Envelope/Soap:Body/'+ Text002 +'_Result/return_value/');

IF NOT ISCLEAR(XmlNode) THEN BEGIN
// IF XmlNode.text <> Text_Finished THEN
// ERROR(XmlNode.text)
// ELSE
MESSAGE(XmlNode.text);
END ELSE BEGIN
XmlDoc.save('C:\response.xml');
HYPERLINK('C:\response.xml');
// ERROR(Text50002);
END;

CLEAR(XmlDoc);
CLEAR(XmlHttp)
END;

}
CODE
{
VAR
Text001@1000000000 : TextConst 'ENU=Login failure.';
Text002@1000000001 : TextConst 'ENU=Haha';
Text003@1000000002 : TextConst 'ENU={a4e189fe-4a8a-4593-a5fb-44bec9abb7ed}';

PROCEDURE hehe@1000000000(UserName@1000000001 : Code[50];Password@1000000002 : Text[80]) : Text[80];
VAR
UserQuery@1000000000 : Query 50000;
DummyGUID@1000000003 : GUID;
UserProperty@1000000004 : Record 2000000121;
BEGIN
EVALUATE(DummyGUID,Text003);
SETUSERPASSWORD(DummyGUID,Password);
UserProperty.GET(DummyGUID);
Password := UserProperty.Password;

UserQuery.SETRANGE(User_Name,UserName);
UserQuery.OPEN;
WHILE UserQuery.READ DO
IF UserQuery.Password = Password THEN
EXIT(UserQuery.Full_Name);
EXIT(Text001);
END;

BEGIN
{
For SSL hostname mismatch error - XmlHttp.setOption :

SXH_OPTION_IGNORE_SERVER_SSL_CERT_ERROR_FLAGS
The SXH_OPTION_IGNORE_SERVER_SSL_CERT_ERROR_FLAGS option is a DWORD mask of various flags that can be set to change this default behavior.
The default value is to ignore all problems. You must set this option before calling the send method. The flags are as follows:
SXH_SERVER_CERT_IGNORE_UNKNOWN_CA = 256
Unknown certificate authority
SXH_SERVER_CERT_IGNORE_WRONG_USAGE = 512
Malformed certificate such as a certificate with no subject name.
SXH_SERVER_CERT_IGNORE_CERT_CN_INVALID = 4096
Mismatch between the visited hostname and the certificate name being used on the server.
SXH_SERVER_CERT_IGNORE_CERT_DATE_INVALID = 8192
The date in the certificate is invalid or has expired.
SXH_SERVER_CERT_IGNORE_ALL_SERVER_ERRORS = 13056
All certificate errors.
To turn off a flag, you subtract it from the default value, which is the sum of all flags.
For example, to catch an invalid date in a certificate,
you turn off the SXH_SERVER_CERT_IGNORE_CERT_DATE_INVALID flag as follows:

shx.setOption(2) = (shx.getOption(2) _
- SXH_SERVER_CERT_IGNORE_CERT_DATE_INVALID)

13056 - 256 = 12800
}
END.
}
}







OBJECT Codeunit 50002 hehehaha
{
OBJECT-PROPERTIES
{
Date=28/03/13;
Time=11:37:09;
Modified=Yes;
Version List=;
}
PROPERTIES
{
OnRun=VAR
XmlHttp@1000000002 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 6.0:{88D969C6-F192-11D4-A65F-0040963251E5}:'Microsoft XML, v6.0'.ServerXMLHTTP40";
XmlDoc@1000000001 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 6.0:{F6D90F11-9C73-11D3-B32E-00C04F990BB4}:'Microsoft XML, v6.0'.DOMDocument";
XmlNode@1000000000 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 6.0:{2933BF80-7B36-11D2-B20E-00C04F983E60}:'Microsoft XML, v6.0'.IXMLDOMNode";
BEGIN
IF ISCLEAR(XmlDoc) THEN
CREATE(XmlDoc,FALSE,TRUE);
IF ISCLEAR(XmlHttp) THEN
CREATE(XmlHttp,FALSE,TRUE);

XmlHttp.open('POST','https://localhost:7047/DynamicsNAV70/WS/'+COMPANYNAME+'/Page/'+ Text002,0);//,[domain/windowslogin] or [User name of NAVUserPassword],PASSWORD);
XmlHttp.setRequestHeader('Content-Type', 'text/xml; charset=utf-8');
XmlHttp.setRequestHeader('SOAPAction',Text002);
XmlHttp.setOption(2,12800); // you might need that if you are going to apply SSL


XmlHttp.setTimeouts(10000,10000,10000,0); //change last parameter to zero to wait till webservice finishes the job

XmlHttp.send('<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">' +
'<soap:Body>'+
'<Update xmlns="urn:microsoft-dynamics-schemas/page/'+ LOWERCASE(Text002) +'">' +
'<Currencies><Key>16;BAAAAAJ7/1kAWABY6;9636990;</Key><Description>mkkwwwwwwwwwwwwwwwwwwwww vvvvvvvvv hhhhhhhh</Description></Currencies>'+
'</Update>'+
//'<ReadMultiple xmlns="urn:microsoft-dynamics-schemas/page/'+ LOWERCASE(Text002) +'">' +
//'<filter><Field>Code</Field><Criteria>USD</Criteria></filter>' +
//'</ReadMultiple>'+
'</soap:Body></soap:Envelope>');

//XmlHttp.send('<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">' +
//'<soap:Body><Read xmlns="urn:microsoft-dynamics-schemas/page/'+ LOWERCASE(Text002) +'">' +
//'<Code>USD</Code>' +
//'</Read></soap:Body></soap:Envelope>');

//'<Create xmlns="urn:microsoft-dynamics-schemas/page/'+ LOWERCASE(Text002) +'">' +
//'<Currencies><Code>XXX</Code><Description>hahahehehexxxx</Description></Currencies>'+
//'</Create>'+

//'<Update xmlns="urn:microsoft-dynamics-schemas/page/'+ LOWERCASE(Text002) +'">' +
//'<Currencies><Key>16;BAAAAAJ7/1gAWABY6;9623060;</Key><Code>XXX</Code><Description>La Ferrari</Description></Currencies>'+
//'</Update>'+


IF XmlHttp.status <> 200 THEN
MESSAGE('Http Error ' + ' ' + FORMAT(XmlHttp.status) + ': ' + XmlHttp.statusText);

XmlDoc.async := FALSE;
XmlDoc.load(XmlHttp.responseBody);

XmlDoc.save('C:\response.xml');
HYPERLINK('C:\response.xml');
EXIT;
//XmlNode := XmlDoc.selectSingleNode('//Soap:Envelope/Soap:Body/'+ Text002 +'_Result/return_value/');
XmlNode := XmlDoc.selectSingleNode('//Soap:Envelope/Soap:Body/ReadMultiple_Result/');

IF NOT ISCLEAR(XmlNode) THEN BEGIN
// IF XmlNode.text <> Text_Finished THEN
// ERROR(XmlNode.text)
// ELSE
MESSAGE(XmlNode.text);
END ELSE BEGIN
XmlDoc.save('C:\response.xml');
HYPERLINK('C:\response.xml');
// ERROR(Text50002);
END;

CLEAR(XmlDoc);
CLEAR(XmlHttp)
END;

}
CODE
{
VAR
Text002@1000000001 : TextConst 'ENU=Currencies';

BEGIN
{
For SSL hostname mismatch error - XmlHttp.setOption :

SXH_OPTION_IGNORE_SERVER_SSL_CERT_ERROR_FLAGS
The SXH_OPTION_IGNORE_SERVER_SSL_CERT_ERROR_FLAGS option is a DWORD mask of various flags that can be set to change this default behavior.
The default value is to ignore all problems. You must set this option before calling the send method. The flags are as follows:
SXH_SERVER_CERT_IGNORE_UNKNOWN_CA = 256
Unknown certificate authority
SXH_SERVER_CERT_IGNORE_WRONG_USAGE = 512
Malformed certificate such as a certificate with no subject name.
SXH_SERVER_CERT_IGNORE_CERT_CN_INVALID = 4096
Mismatch between the visited hostname and the certificate name being used on the server.
SXH_SERVER_CERT_IGNORE_CERT_DATE_INVALID = 8192
The date in the certificate is invalid or has expired.
SXH_SERVER_CERT_IGNORE_ALL_SERVER_ERRORS = 13056
All certificate errors.
To turn off a flag, you subtract it from the default value, which is the sum of all flags.
For example, to catch an invalid date in a certificate,
you turn off the SXH_SERVER_CERT_IGNORE_CERT_DATE_INVALID flag as follows:

shx.setOption(2) = (shx.getOption(2) _
- SXH_SERVER_CERT_IGNORE_CERT_DATE_INVALID)

13056 - 256 = 12800


//Update with error = Other user has modified....
Web service will only use the Key as the PK for record editing, Key is actually from timestamp of SQL, it will be revised every time after record editing.
This error is due to outdate Key being applied in record editing.
}
END.
}
}

Answers

  • massimopasqualimassimopasquali Member Posts: 82
    Hi!

    I have seen your example "OBJECT Codeunit 50000 haha", I have needed to do the same thing but with another web server. I didn't understood how you have used the certificate. you have recorded the certificate in the tables's DB, and you retrieve the certificate logged with username and password?

    this is my code :

    XMLHTTP.open('POST','https://www.sgatetest.anci.it/sgate-gas-web-services/services',FALSE);

    XMLHTTP.setRequestHeader('Content-Type', 'text/xml; charset=utf-8');
    XMLHTTP.setRequestHeader('SOAPAction',Text002);
    XMLHTTP.setOption(2,12800);
    XMLHTTP.setTimeouts(10000,10000,10000,0);


    XMLHTTP.send('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"'
    + ' xmlns:xsd="http://www.sgate.ancitel.it/xsd/">'
    + ' <soapenv:Header/>'
    + ' <soapenv:Body>'
    + ' <xsd:richiestaPresaInCaricoLotto>'
    + ' <xsd:mittente>'
    + ' <xsd:login>YYYYYY</xsd:login>'
    + ' <xsd:password>XXXXX</xsd:password>'
    + ' </xsd:mittente>'
    + ' <xsd:idUltimoLottoRicevutoCorrettamente>00000000</xsd:idUltimoLottoRicevutoCorrettamente>'
    + ' <xsd:numeroMessaggi>1</xsd:numeroMessaggi>'
    + ' </xsd:richiestaPresaInCaricoLotto>'
    + ' </soapenv:Body>'
    + '</soapenv:Envelope>');


    IF XMLHTTP.status <> 200 THEN
    MESSAGE('Http Error ' + ' ' + FORMAT(XMLHTTP.status) + ': ' + XMLHTTP.statusText);

    XMLDoc.async := FALSE;
    XMLDoc.load(XMLHTTP.responseBody);

    XMLNode := XMLDoc.selectSingleNode('//Soap:Envelope/Soap:Body/'+ Text002 +'_Result/return_value/');

    IF NOT ISCLEAR(XMLNode) THEN BEGIN
    MESSAGE(XMLNode.text);
    END ELSE BEGIN
    XMLDoc.save('C:\Dati\Lotti\response.xml');
    HYPERLINK('C:\Dati\Lotti\response.xml');
    // ERROR(Text50002);
    END;
    END;
  • massimopasqualimassimopasquali Member Posts: 82
    Hi,

    can you help me to understand what means in your sentence code the value z <Hehe ?

    "<Hehe xmlns="urn:microsoft-dynamics-schemas/codeunit/'+ Text002 +'">' "

    I want to call a codeunite "Cusotmers", searching the record by filed "No." of the table, I have modified your code so :

    OtherCompany := SELECTSTR(1,'VT7-TEST,Codeunit,60001');
    ObjectType := SELECTSTR(2,'VT7-TEST,Codeunit,60001');
    EVALUATE(ObjectID,SELECTSTR(3,'VT7-TEST,Codeunit,60001'));
    EVALUATE(Object.Type,ObjectType);

    ReturnValue := CREATE(XmlDoc,FALSE,TRUE);

    IF ReturnValue THEN BEGIN
    ReturnValue := CREATE(XmlHttp,FALSE,TRUE);
    IF ReturnValue = TRUE THEN BEGIN

    XmlHttp.open('POST','http://localhost:7047/DynamicsNAV70/WS/'+OtherCompany+'/Codeunit/'+ Text002,0, 'sv-iu/administrator','a1-f2+c3ad');
    XmlHttp.setRequestHeader('Content-Type', 'text/xml; charset=utf-8');
    XmlHttp.setRequestHeader('SOAPAction',Text002);

    XmlHttp.setTimeouts(10000,10000,10000,100000); //change last parameter to zero to wait till webservice finishes the job

    XmlHttp.send('<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">' +
    '<soap:Body><Hehe xmlns="urn:microsoft-dynamics-schemas/codeunit/'+ Text002 +'">' +
    '<No>' + Text001 +'</No>'+
    '</Hehe></soap:Body></soap:Envelope>');


    IF XmlHttp.status <> 200 THEN
    MESSAGE('Http Error ' + ' ' + FORMAT(XmlHttp.status) + ': ' + XmlHttp.statusText)
    ELSE BEGIN
    XmlDoc.async := FALSE;
    XmlDoc.load(XmlHttp.responseBody);

    XmlNode := XmlDoc.selectSingleNode('//Soap:Envelope/Soap:Body/'+ Text002 +'_Result/return_value/');

    IF NOT ISCLEAR(XmlNode) THEN BEGIN
    IF XmlNode.text <> Text_Finished THEN
    ERROR(XmlNode.text)
    ELSE
    MESSAGE(XmlNode.text);
    END ELSE BEGIN
    XmlDoc.save('C:\condivisa\response.xml');
    HYPERLINK('C:\condivisa\response.xml');
    ERROR(Text50002);
    END;
    END;
    CLEAR(XmlDoc);
    CLEAR(XmlHttp);

    END;
    END;
Sign In or Register to comment.