Return JSON From D365 Business Events:

Share this:

Why Do We Need To Return JSON From D365 Business Events?

D365 Business Events are intended to just return a small amount of data to a receiving system, such as a status. But what if you need to return some complex data? Such as the status of each sales line in a sales order? You need to return an array of data. However, arrays are not supported in Business Events. Neither are complex data types such as classes. One way we can meet this need is to return JSON from D365 Business Events in a single string. JSON can contain the complex data we need to represent, and allow the receiving system understand all of the individual and dynamic list of values.

Storing JSON In The Contract Class

In the last article we explained how to setup a custom business event: https://dynamics365musings.com/how-to-setup-a-custom-d365-business-event/

And that a custom business event requires three things:

  1. A contract class that defines the details of the message to be sent.
  2. A Business Event class, that maps the data from the D365 object to the contract class.
  3. The chain of command method that creates the business event during the appropriate operation.

In the contract class, the code takes the D365 information and maps it to the business event message. In our case, we will read the status from each sales line on a sales order, and put it inside of a JSON string. Then store this JSON string in our business event message.

Declare a class variable for storing the JSON data, as well as declare a couple of variables we will use as part of the process.

    private Str1260 salesLineData;

    System.IO.StringWriter          stringWriter;
    Newtonsoft.Json.JsonTextWriter  jsonWriter;

Create a method named GetSalesLineData. Populate it with the code below. The code uses a while select to loop through all of our sales line records for the sales order. Inside the loop, use the Newtonsoft.Json.JsonTextWriter to build a json string, setting the various values to be included in the business event message. Finally the code returns the fully constructed JSON string.

    private Str1260 GetSalesLineData( SalesId _salesId)
    {
        SalesLine salesLine;
        CustInvoiceTrans custInvoiceTrans;
        CustPackingSlipTrans custPackingSlipTrans;
        stringWriter = new System.IO.StringWriter();
        jsonWriter = new Newtonsoft.Json.JsonTextWriter(stringWriter);
        jsonWriter.WriteStartArray();
        while select salesLine
            where salesLine.SalesId == _salesId
        {
            // Add line data to parm object
            jsonWriter.WriteStartObject();
            jsonWriter.WritePropertyName("LineNumberExternal");
            jsonWriter.WriteValue(salesLine.rsmLineNumberExternal);
            jsonWriter.WritePropertyName("LineQuantity");
            jsonWriter.WriteValue(salesLine.SalesQty);
            jsonWriter.WritePropertyName("LineDelivered");
            select sum(Qty) from custPackingSlipTrans
                where custPackingSlipTrans.InventTransId == salesLine.InventTransId;
            jsonWriter.WriteValue(custPackingSlipTrans.Qty);
            jsonWriter.WritePropertyName("LineInvoiced");
            select sum(Qty) from custInvoiceTrans
                where custInvoiceTrans.InventTransId == salesLine.InventTransId;
            jsonWriter.WriteValue(custInvoiceTrans.Qty);
            jsonWriter.WritePropertyName("LineStatus");
            jsonWriter.WriteValue(salesLine.SalesStatus);
            jsonWriter.WriteEndObject();
        }
        jsonWriter.WriteEndArray();
        return stringWriter.ToString();
    }

In the initialize method, call the method GetSalesLineData and set the JSON string value to the local class variable named salesLineData.

    private void initialize(SalesTable _salesTable)
    {
        CustParameters custParameters = CustParameters::find();
        salesId = _salesTable.SalesId;
        salesStatus = enum2Symbol(enumNum(SalesStatus), _salesTable.SalesStatus);
        salesLineData = this.GetSalesLineData(_salesTable.SalesId);
    }

Finally create the method parmSalesLineData method with a ‘DataMember’ attribute. This tells the system that this is a value we want to be included in the business event message.

[DataMember('SalesLineData'), BusinessEventsDataMember("@AccountsReceivable:SalesLineData")]
    public Str1260 parmSaleLineData(Str1260 _salesLineData = salesLineData)
    {
        salesLineData = _salesLineData;

        return salesLineData;
    }

Conclusion

Typically in business events, each property in the contract class will contain a single value with a single purpose. Since Business Events do not allow us to return an array of values, or a complex object such as another class, we need to get creative. While we can return XML or comma separated data in a single string. JSON is the best choice for storing the data in this case. We then store the JSON value into a single property on our Business Event message. This does mean that the JSON string will need to be parsed and interpreted when it is received by whatever system receives the business event message. But the benefit is that it allows us to send more complex information than D365 Business Events normally allow by themselves.

Complete Code To Return JSON Data from D365 Business Events

/// <summary>
/// The data contract for a <c>rsmPackSlipPostedBusinessEvent</c>.
/// </summary>
[DataContract]
public final class rsmPackSlipPostedBusinessEventContract extends BusinessEventsContract
{
    //private RecId recordId;
    private SalesIdBase salesId;
    private LegalEntityDataAreaId legalEntity;
    private String50 salesStatus;
    private Str1260 salesLineData;

    System.IO.StringWriter          stringWriter;
    Newtonsoft.Json.JsonTextWriter  jsonWriter;
  
    /// <summary>
    /// Creates a <c>rsmPackSlipPostedBusinessEventContract</c> from a <c>CustInvoiceJour</c> record.
    /// </summary>
    /// <param name = "_custInvoiceJour">A <c>CustInvoiceJour</c> record.</param>
    /// <returns>A <c>rsmPackSlipPostedBusinessEventContract</c>.</returns>
    public static rsmPackSlipPostedBusinessEventContract newFromSalesTable(SalesTable _salesTable)
    {
        var contract = new rsmPackSlipPostedBusinessEventContract();
        contract.initialize(_salesTable);

        return contract;
    }

    private void initialize(SalesTable _salesTable)
    {
        CustParameters custParameters = CustParameters::find();
        salesId = _salesTable.SalesId;
        salesStatus = enum2Symbol(enumNum(SalesStatus), _salesTable.SalesStatus);
        salesLineData = this.GetSalesLineData(_salesTable.SalesId);
    }

    private void new()
    {
    }

    private Str1260 GetSalesLineData( SalesId _salesId)
    {
        SalesLine salesLine;
        CustInvoiceTrans custInvoiceTrans;
        CustPackingSlipTrans custPackingSlipTrans;
        stringWriter = new System.IO.StringWriter();
        jsonWriter = new Newtonsoft.Json.JsonTextWriter(stringWriter);
        jsonWriter.WriteStartArray();
        while select salesLine
            where salesLine.SalesId == _salesId
        {
            // Add line data to parm object
            jsonWriter.WriteStartObject();
            jsonWriter.WritePropertyName("LineNumberExternal");
            jsonWriter.WriteValue(salesLine.rsmLineNumberExternal);
            jsonWriter.WritePropertyName("LineQuantity");
            jsonWriter.WriteValue(salesLine.SalesQty);
            jsonWriter.WritePropertyName("LineDelivered");
            select sum(Qty) from custPackingSlipTrans
                where custPackingSlipTrans.InventTransId == salesLine.InventTransId;
            jsonWriter.WriteValue(custPackingSlipTrans.Qty);
            jsonWriter.WritePropertyName("LineInvoiced");
            select sum(Qty) from custInvoiceTrans
                where custInvoiceTrans.InventTransId == salesLine.InventTransId;
            jsonWriter.WriteValue(custInvoiceTrans.Qty);
            jsonWriter.WritePropertyName("LineStatus");
            jsonWriter.WriteValue(salesLine.SalesStatus);
            jsonWriter.WriteEndObject();
        }
        jsonWriter.WriteEndArray();
        return stringWriter.ToString();
    }

[DataMember('SalesLineData'), BusinessEventsDataMember("@AccountsReceivable:SalesLineData")]
    public Str1260 parmSaleLineData(Str1260 _salesLineData = salesLineData)
    {
        salesLineData = _salesLineData;

        return salesLineData;
    }


    [DataMember('SalesOrderId'), BusinessEventsDataMember("@AccountsReceivable:SalesOrderId")]
    public SalesIdBase parmSaleOrderId(SalesIdBase _salesId = salesId)
    {
        salesId = _salesId;

        return salesId;
    }

    [DataMember('SalesStatus'), BusinessEventsDataMember("@AccountsReceivable:SalesStatus")]
    public String50 parmSalesStatus(String50 _salesStatus = salesStatus)
    {
        salesStatus = _salesStatus;
        return salesStatus;
    }

    [DataMember('LegalEntity'), BusinessEventsDataMember("@AccountsReceivable:LegalEntity")]
    public LegalEntityDataAreaId parmLegalEntity(LegalEntityDataAreaId _legalEntity = legalEntity)
    {
        legalEntity = _legalEntity;

        return legalEntity;
    }

    
}

Peter Ramer
Peter Ramer is a part of the Managed Application Services team at RSM working on Microsoft Dynamics 365. He focuses on the Retail and Commerce industries. When he is not solving problems and finding ways to accelerate his clients' business, he enjoys time with his three kids and amazing wife.

Share this:

One thought on “Return JSON From D365 Business Events:

Add yours

Leave a Reply

Your email address will not be published. Required fields are marked *

Proudly powered by WordPress | Theme: Baskerville 2 by Anders Noren.

Up ↑