Quantcast
Channel: Forums - Recent Threads
Viewing all articles
Browse latest Browse all 143529

Serializing and deserializing Json in AX

$
0
0

Hi all,

I recently had a project that involved getting data into and out of AX 2012 using Json strings and thought I'd blog it here. I know D365 is being used more and more, but thought it might still be useful for someone.

The requirement was to integrate various transactions with a 3rd party Retail package, so we exposed some methods to a web service hosted in AX (Inbound ports form). Reading elsewhere about AX 2012 not having lots of Json support built-in, we decided to use the free NewtonSoft Json.NET library.

Add the DLL as a reference in AX (after copying it to both server\bin and client\bin directories, or using the GAC). 

Serialization

Serializing to a Json string works perfectly in AX by using a DataContractAttribute class to build the data. For example, if you need to send Customer information, you can create a class as follows:

[DataContractAttribute]
public class CustMaster
{
    CustAccount     accountNum;
    Name            firstName,
                    lastName;
    PhoneLocal      custPhone;
    Email           custMail;
}

[DataMemberAttribute("Customer code")]
public CustAccount parmCustAccountNum(CustAccount _accountNum = accountNum)
{
    accountNum = _accountNum;
    return accountNum;
}

[DataMemberAttribute("First name")]
public Name parmFirstName(Name _firstName = firstName)
{
    firstName = _firstName;
    return firstName;
}

[DataMemberAttribute("Last name")]
public Name parmLastName(Name _lastName = lastName)
{
    lastName = _lastName;
    return lastName;
}

[DataMemberAttribute("Phone 1")]
public PhoneLocal parmPhone(PhoneLocal _custPhone = custPhone)
{
    custPhone = _custPhone;
    return custPhone;
}

[DataMemberAttribute("Email")]
public Email parmEmail(Email _custMail = custMail)
{
    custMail = _custMail;
    return custMail;
}

The names corresponding to each variable, such as "Phone 1" are created as the tags in the Json string.

Using the above contract, we can create a Json string to send out by looping through the CustTable and adding each record to the string as follows:

[SysEntryPointAttribute]
public str getCustomers()
{
    CustTable                       cTable;
    str                             custStr = '';
    System.Exception                clrException;
    System.Object                   custObj;
    InteropPermission               permission;
    System.Collections.ArrayList    list = new System.Collections.ArrayList();
    CustMaster                      custContract;
    
    try
    {
        permission = new InteropPermission(InteropKind::ClrInterop);
        permission.assert();

        while select cTable
        {
            custContract = new CustMaster();
            custContract.parmCustAccountNum(cTable.AccountNum);
            custContract.parmFirstName(cTable.Name());
            custContract.parmLastName(cTable.Name());
            custContract.parmPhone(cTable.phoneLocal());
            custContract.parmEmail(cTable.email());

            custObj = CLRInterop::getObjectForAnyType(custContract);
            list.Add(custObj);
        }

        if (list.get_Count() > 0)
        {
            custStr = Newtonsoft.Json.JsonConvert::SerializeObject(list, Newtonsoft.Json.Formatting::Indented);
        }

        CodeAccessPermission::revertAssert();
    }
    catch (Exception::CLRError)
    {
        // BP deviation documented
        clrException = CLRInterop::getLastException();
        if (clrException != null)
        {
            //BP Deviation Documented
            info(CLRInterop::getAnyTypeForObject(clrException.get_Message()));
            while (clrException != null)
            {
                clrException = clrException.get_InnerException();
                if (clrException == null)
                    break;
                checkFailed(CLRInterop::getAnyTypeForObject(clrException.ToString()));
            }
        }
        throw error("Failed");
    }

The output will look like the following:

[
  {
    "Customer code": "CUS001",
    "Email": "",
    "First name": "TEST CUSTOMER ONE",
    "Last name": "TEST CUSTOMER ONE",
    "Phone 1": ""
  },
  {
    "Customer code": "CUS002",
    "Email": "",
    "First name": "TEST CUSTOMER TWO",
    "Last name": "TEST CUSTOMER TWO",
    "Phone 1": ""
  },
  {
    "Customer code": "CUS003",
    "Email": "",
    "First name": "TEST CUSTOMER THREE",
    "Last name": "TEST CUSTOMER THREE",
    "Phone 1": ""
  }
]

Deserialization

For deserializing, it works slightly different. It doesn't seem like you can cast to an AX DataContractAttribute class from a .NET object (or at least I wasn't able to), so you will need to create a C# class and add that DLL as a reference in your AX environment as well. You can then call the Get_<parameterName>() methods directly from the .NET class.

Create the .NET class:

using System;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Serialization;

namespace RetailClasses
{
    [DataContract]
    public class CustOrders
    {
        [DataMember(Name = "CustomerAccount")]
        public string AccountNum { get; set; }

        [DataMember(Name = "CustomerReference")]
        public string CustReference { get; set; }

        [DataMember]
        public DateTime ShipmentDate { get; set; }

        [DataMember(Name = "SalesOrderLines")]
        public ArrayList OrderLines { get; set; }
    }

    [DataContract]
    public class CustOrderLines
    {
        [DataMember(Name = "ItemNumber")]
        public string ItemId { get; set; }

        [DataMember(Name = "Qty")]
        public float Quantity { get; set; }

        [DataMember(Name = "Colour")]
        public string ItemColour { get; set; }

        [DataMember(Name = "Size")]
        public string ItemSize { get; set; }
    }
}

After adding this reference in AX, you can use the code as follows:

[SysEntryPointAttribute]
public boolean createOrder(str _orderStr)
{
    InteropPermission               permission;
    System.Exception                clrException;
    Newtonsoft.Json.Linq.JArray     list = new Newtonsoft.Json.Linq.JArray();
    Newtonsoft.Json.Linq.JObject    jObject;
    System.Collections.IEnumerator  lEnum;
    RetailClasses.CustOrders        orders = new RetailClasses.CustOrders();

    void processSalesQuote(RetailClasses.CustOrders _custOrders)
    {
        CustomerReference       custRef;
        CustAccount             custAccount;
        date                    shipDate;
        //SalesOrderLines;
        ItemId                  itemNumber;
        Qty                     qtyOrdered;
        EcoResItemColorName     colour;
        EcoResItemSizeName      size;
        RetailClasses.CustOrderLines     orderLines = new RetailClasses.CustOrderLines();
        System.Collections.ArrayList    linesList = new  System.Collections.ArrayList();
        System.Collections.IEnumerator  lEnum;
        Newtonsoft.Json.Linq.JObject    jObject;
    
        custRef = _custOrders.get_CustReference();
        custAccount = _custOrders.get_AccountNum();
        shipDate = _custOrders.get_ShipmentDate();

        linesList = _custOrders.get_OrderLines();
        lEnum = linesList.GetEnumerator();

        // Create Header
        ...
        // create lines
        while (lEnum.MoveNext())
        {
            jObject = lEnum.get_Current();
            orderLines = Newtonsoft.Json.JsonConvert::DeserializeObject(jObject.ToString(), orderLines.GetType());

            size = orderLines.get_ItemSize();
            colour = orderLines.get_ItemColour();
            itemNumber = orderLines.get_ItemId();
            qtyOrdered = orderLines.get_Quantity();
            ...
        }
    }

    try
    {
        permission = new InteropPermission(InteropKind::ClrInterop);
        permission.assert();

        list = Newtonsoft.Json.JsonConvert::DeserializeObject(_orderStr, list.GetType());
        lEnum = list.GetEnumerator();

        while (lEnum.MoveNext())
        {
            jObject = lEnum.get_Current();

            orders = Newtonsoft.Json.JsonConvert::DeserializeObject(jObject.ToString(), orders.GetType());

            processSalesQuote(orders);
        }
    }
    catch (Exception::CLRError)
    {
        // BP deviation documented
        clrException = CLRInterop::getLastException();
        if (clrException != null)
        {
            //BP Deviation Documented
            info(CLRInterop::getAnyTypeForObject(clrException.get_Message()));
            while (clrException != null)
            {
                clrException = clrException.get_InnerException();
                if (clrException == null)
                    break;
                checkFailed(CLRInterop::getAnyTypeForObject(clrException.ToString()));
            }
        }
        ret = checkFailed("Failed");
    }
}

Viewing all articles
Browse latest Browse all 143529

Trending Articles