3 Ekim 2020 Cumartesi

AX 2012 - Using Rest Api with AX

One of the our customers of AX partner which I work AGC Software applied a service requires using Rest Api. I found different samples on forums and blogs about AX 2012 but succeeded none of them. At that point I dediced to start from beginning.

At first I installed Postman to my computer. Succeeded to run service with Postman

Now I have C# RestSharp library code written by Postman's code generator:





I needed import RestSharp library into my project before have a code deployable by AX. When tried to import by command written in Visual Studio 2013 Package Manager Console :

Install-Package RestSharp 





I got "The underlying connection was closed: An unexpected error occurred on a send." error. Found solution on a forum page. When i wrote code below to a .REG file and run than I could install  Nuget packages:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319]
"SchUseStrongCrypto"=dword:00000001

[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319]
"SchUseStrongCrypto"=dword:00000001


But than I see the last version of RestSharp doesn't compatible with Visual Studio 2013 :





Learned last RestSharp version which works with Visual Studio 2013 from another forum page  than I could import:

Install-Package RestSharp -Version 103.1.0

Now I had a working and deployable code with AX:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RestSharp;

namespace Ingenico
{
    public class Ingenico
    {
        public string StartDate { get; set; }
        public string EndDate { get; set; }
        public string Body { get; set; }
        public string Idx { get; set; }
        public string getPaymentSummaryReport()
        {
            var client = new RestClient("https://XXXXXXXXXXXXXXX/GetPaymentSummaryReport");
            client.Timeout = -1;
            var request = new RestRequest(Method.POST);
            request.AddHeader("Operator", "XXXXXXX");
            request.AddHeader("Authorization", "Basic XXXXXXX");
            request.AddHeader("Content-Type", "application/json");
            Body = "{\r\n\"ReportId\": "+Idx+",\r\n\"SerialList\": [\r\n\"\"\r\n],\r\n\"StartDate\": \""+StartDate+
            "\",\r\n\"EndDate\": \""+EndDate+
            "\",\r\n\"ExternalField\": \"\",\r\n\"ReceiptNo\": 0,\r\n\"ZNo\": 0,\r\n\"GetSummary\": true,\r\n\"SaleFlags\": 0,\r\n\"DeviceGroupName\": \"\"\r\n}\r\n       \r\n";
            request.AddParameter("application/json",Body, ParameterType.RequestBody);
            IRestResponse response = client.Execute(request);
            return response.Content;
        }
    }
}


When I deployed code, I saw it looks for  RestSharp.DLL and RestSharp.XML files reside in project folder and AX doesn't copy them to bin folder. Copied these files to server and client bin folders:



Then I could use the service:

    Ingenico.Ingenico o = new Ingenico.Ingenico();
    str a;

    try
    {
        o.set_StartDate("2020-10-01");
        o.set_EndDate("2020-10-01");
        o.set_Idx("111111111111");
        a = o.getPaymentSummaryReport();

    info(a);


I used  another blog for parse Json string which came from service.

 

class AGCingenico
{
    Array           jsonArray;
 
}

At first parse Json string with this method:

void parseJson(str  _json)

{
   Array           jsonArray;
   container       con;

   int             jsonSubstrNo, i;

   TextBuffer      textBuffer;

   Array           returnArray = new Array(Types::Class);

   #Define.LBracket('{')

   #Define.RBracket('}')
    str st;
    int fnd;



    fnd = strScan(_json,"]",1,strLen(_json));

    st="{"+subStr(_json,fnd+2,strlen(_json) - fnd -1);
    con+=st;



   // extract the json substrings and add them to a Array

   textBuffer = new TextBuffer();

   textBuffer.setText(_json);

   while (textBuffer.nextToken(0, #LBracket+#RBracket))

   {

       if ((jsonSubstrNo mod 2) > 0)
       {
           st =#LBracket + textBuffer.token() + #RBracket;
           con += st;
       }
       jsonSubstrNo++;

   }


   for (i = 1; i <= conLen(con); i++)

   {

       returnArray.value(i, RetailCommonWebAPI::getMapFromJsonString(conPeek(con, i)));

   }

   jsonArray = returnArray;

}

Than insert values a table with this method:

void jsonToTable()
{
   MapIterator                 mi;
   Map                         data;
   int                         i;
   str                         value;
   

   for (i = 1; i <= jsonArray.lastIndex(); i++)
   {
       data = jsonArray.value(i);
       mi = new MapIterator(data);
       tmpTable.clear();

       while (mi.more())
       {
           value = data.lookup(mi.key());
     
           switch (mi.key())
           {
               case "ErrCode":
                this.parmErrCode(str2int(value));
                break;
               case "ErrDesc":
                this.parmErrStr(value);
                break;
               case "Amount":
                tmpTable.Amount = str2num_RU(value);
                break;
               case "AmountCredit":
                tmpTable.AmountCredit = str2num_RU(value);
                break;

...

...

...


When I was thinking all well done there was another surprise. Code was working good with client side but not in CIL was giving an error about type convert. I found solution from a  forum page again. Martin Drab described pinpoint solution. Modified RetailCommonWebAPI class like this and all errors was fixed:

//AGC memre 29.9.20
//private static Map getMap(CLRObject _dict)
private static Map getMap(System.Collections.IDictionary _dict)
//http://dev.goshoom.net/en/2016/01/x-to-cil-object-must-implement-iconvertible/#comment-135186
//AGC memre
{


At last it's easy to use Rest Api with AX 2012 but there're lots of issues need to touch, fortunately there're lots of forums pages and blogs. :)