The Dynamics 365FO Business Events functionality is currently available as a preview feature since the release of Dynamics 365 Finance and Operations Platform Update 24. With the new Business Events functionality, we can finally integrate D365FO directly with workflow based cloud development tools like Flow and Logic apps.
Here in this article I will demonstrate how to create a new D365FO Business Event and use it directly from a Microsoft Flow using the new D365FO “When a Business Event occurs” trigger.

Enabling Business Events in D365FO

First let’s enable the business events feature and start the batch job for it. The Business Events parameters should be available as a separate tab in System administration>Setup>System parameters form (In this article, I use a PU25 environment, and description below is for preview version only! Updates will be mentioned seperately):

Note : Preview version only!

If you cannot see it there, it is because the feature is currently in preview mode, and you need to use LCS or do some magic to make it visible. For the magic part; first go to SQL Management tool, open a new query window for your AxDB and run the following sql query :

INSERT INTO SYSFLIGHTING (FLIGHTNAME, ENABLED, FLIGHTSERVICEID) VALUES ('BusinessEventsMaster', 1, 12719367)

Then go to your web.config file for AX and make sure these values in it look like this :

<add key="DataAccess.FlightingEnvironment" value="" />;
<add key="DataAccess.FlightingCertificateThumbprint" value="1c2b9bb178c4303d269c39ddf9306ae374129381"/>
<add key="DataAccess.FlightingServiceCatalogID" value="12719367" />

Then restart your iis, and you should be able to see the tab now. If not, try restarting iis couple of times, sometimes it does not work immediately.

Enable business events by clicking enable here and click on the Start business events job button to setup the events batch. Well; in Microsoft documentation it states that running the batch job is not needed and only to be used in special situations but in my tests it did not work if I did not start it.. :

Blog Update
After PU27 business events is released to general availability and there are important changes to what is described here. The enable-disable button shown above does not exists anymore, and the whole feature comes disabled in non-production environments. Now, You need to make a change to AX database to enable the events job. For that, execute the following command for AXDB, then restart everything (IIS, batch service..) :
UPDATE [dbo].[BUSINESSEVENTSPARAMETERS]
SET [BATCHENABLED] = 1
,[PROCESSORTHREADS] = 1
,[ENDPOINTRETRYCOUNT] = 3
,[BUNDLESIZE] = 50
,[ENDPOINTSPEREVENT] = 10
GO

You do not need to run the batch job anymore once you enabled the functionality.

Further updates are described at the end of the document.

Creating a new business event

In this demo I will create a new one from scratch to show all the process involved. As a trigger data source, I will use my visit schedule service project which I have been using in my other blog posts so far. I have updated this project with added business events and uploaded in my github page (it is optional to use this one, you can use your own data sources to test as well) :

https://github.com/sertanyaman/SertanDevAXExamples/blob/master/AndVisitScheduleWithBusinessEvent.axpp

First you need to create a business event data contract class. This is a simple data contract class that contains fields for the data source you are planning to send and derives from the “BusinessEventsContract” class:

[DataContract]
public class AndVisitScheduleAddedBusinessEventContract extends BusinessEventsContract
{
    int lineNum;
    str custAccount, custName, address;
    utcdatetime visitDateTime;
    HcmPersonnelNumberId	worker;

    public static AndVisitScheduleAddedBusinessEventContract newFromAndVisitSchedule(AndVisitSchedule	_visitSchedule)
    {
        var retVal = AndVisitScheduleAddedBusinessEventContract::construct();
        CustTable	     custTable = _visitSchedule.custTable();


        retVal.parmWorker(_visitSchedule.dispWorkerId());
        retVal.parmCustAccount(_visitSchedule.CustAccount);
        retVal.parmCustName(custTable.name());
        retval.parmAddress(custTable.postalAddress().Address);
        retVal.parmVisitDateTime(_visitSchedule.VisitDateTime);		

        return retVal;
    }

    [DataMember('visitdatetime'), BusinessEventsDataMember('visitdatetime')]
    public utcdatetime parmVisitDateTime( utcdatetime _visitDateTime = visitDateTime )
    {
        visitDateTime = _visitDateTime;

        return visitDateTime;
    }

    [DataMember('worker'), BusinessEventsDataMember('worker')]
    public HcmPersonnelNumberId parmWorker( HcmPersonnelNumberId _worker = worker )
    {
        worker = _worker;

        return worker;
    }

    [DataMember('custaccount'), BusinessEventsDataMember('custaccount')]
    public str parmCustAccount( str _custAccount = custAccount )
    {
        custAccount = _custAccount;

        return custAccount;
    }

    [DataMember('custname'), BusinessEventsDataMember('custname')]
    public str parmCustName( str _custName = custName )
    {
        custName = _custName;

        return custName;
    }

    [DataMember('address'), BusinessEventsDataMember('address')]
    public str parmAddress( str _address = address )
    {
        address = _address;

        return address;
    }

    protected void new()
    {
    }

    public static AndVisitScheduleAddedBusinessEventContract construct()
    {
        AndVisitScheduleAddedBusinessEventContract         retVal = new AndVisitScheduleAddedBusinessEventContract();

        return retVal;
    }

}

See that we need to add both data member and “BusinessEventsDataMember” attributes to define the name of the field. Datamember is used in the schema and a fixed string and the business events data member one is used in the setup form descriptions, which you should better use a Label for.

After the contract is created, create your Business event class deriving from the BusinessEventsBase class as shown below:

[BusinessEvents(classStr(AndVisitScheduleAddedBusinessEventContract), "AndVisitScheduleTest: New visit schedule added", "A new And. visit schedule record added", ModuleAxapta::Basic)]
public final class AndVisitScheduleAddedBusinessEvent extends BusinessEventsBase
{
    private AndVisitSchedule andVisitSchedule;

    private AndVisitSchedule parmAndVisitSchedule(AndVisitSchedule _andVisitSchedule = andVisitSchedule)
    {
        andVisitSchedule = _andVisitSchedule;

        return andVisitSchedule;
    }

    protected void new()
    {
        super();
    }

    public static AndVisitScheduleAddedBusinessEvent construct()
    {
        AndVisitScheduleAddedBusinessEvent         retVal = new AndVisitScheduleAddedBusinessEvent();

        return retVal;
    }

    [Wrappable(true), Replaceable(true)]
    public BusinessEventsContract buildContract()
    {
        return AndVisitScheduleAddedBusinessEventContract::newFromAndVisitSchedule(andVisitSchedule);
    }

    public static AndVisitScheduleAddedBusinessEvent newFromAndVisitSchedule(AndVisitSchedule _andVisitSchedule)
    {
        AndVisitScheduleAddedBusinessEvent	andEvent = AndVisitScheduleAddedBusinessEvent::construct();
        andEvent.parmAndVisitSchedule(_andVisitSchedule);

        return andEvent;
    }

}

The BusinessEvents attribute contains your business event description and the module you want to put it in. Here you should use labels and have a clear description for your event which will be visible in the setup form and event trigger setup in Flow. The code that is executed when your event is send is the “buildContract” method. This method should return the related record via the data contract that is associated with your trigger.

To trigger the event, use the following code in a place you would like the event to triggered. Here I will use the insert method of my visit schedule table :

    public void insert()
    {
        super();

        if (BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(AndVisitScheduleAddedBusinessEvent)))
        {
            AndVisitScheduleAddedBusinessEvent::newFromAndVisitSchedule(this).send();
        }
    }

Now build your project, and go to the Business events setup form. Click on Manage>Rebuild business event catalog and you should see your new business event added to the list :

Testing your new business event

Go to Microsoft Flow and create a new blank flow. From the triggers find the new D365FO “When a Business Event occurs” trigger. Enter your environment name, select the module you set in your business event’s attribute(here in this example, ‘Basic’). And in the list you should see your new business event. Select the company you want to test your event from and that’s it. Now add a new flow step to send a basic e-mail notification to test our event is running and press Save:

As soon as you save your flow in flows editor, D365FO business events should create a new endpoint targeting to that flow and activate your flow automatically to that endpoint. This function, in the time of writing, do not work very well but in my second tryout I was able to get an automatically created endpoint and activation record :

Now let’s test our flow, I add a new record to my visit schedule table:

And my flow gets successfully executed :

And I get my e-mail from The Microsoft Flow :

How to get data from the business event trigger

We have mentioned that in the time of writing this functionality is still in preview. So if I check the associated Dynamic Content for the trigger from the flow editor, I see nothing…

However I was able to access the fields of the triggering record from Flow’s “triggerBody()” function.

Go to the business event setup page of your trigger and check the field names there. You can also download a JSON schema here and see the actual JSON field names that will be sent in the body of the trigger payload :

You can directly add those fields to parts of your message as shown below, using custom Flow expressions to inquiry the fields in the trigger body. To do so, select the Expression tab in the flow editor and enter the expression as “triggerBody()?[‘your_field_name’]” :

Update the flow and let’s run another test to see if the fields are coming OK:

Looks just fine..

The only problem I had here is the datetime fields. At the time of writing they are being sent in a weird format like ” /Date(1558692174000)/ ” or so and not as an ISO standard datetime string. I think this will improve in time but for now a workaround could be converting the datetime fields to ISO strings in your data contract and send them as a string instead.

Hope you find this article useful and enjoy this fresh feature of D365FO.

Blog update :
Business events feature is now released to general availability. There are some updates to the functionality :

  • Business events setup form is now available from a dedicated Business Events Workspace or from the “System Administration / Setup / Business Events” menu.
  • The enable-disable button shown in the setup screen of Preview does not exists anymore, and the whole feature comes disabled in non-production environments. Now, You need to make a change to AX database to enable the events job. For that, execute the following command for AXDB, then restart everything (IIS, batch service..) :
    UPDATE [dbo].[BUSINESSEVENTSPARAMETERS]
    SET [BATCHENABLED] = 1
    ,[PROCESSORTHREADS] = 1
    ,[ENDPOINTRETRYCOUNT] = 3
    ,[BUNDLESIZE] = 50
    ,[ENDPOINTSPEREVENT] = 10
    GO
  • You do not need to run the batch job anymore once you enabled the functionality.
  • I have mentioned using the triggerBody() function to get the fields from the event. In updated official documentation now it mentions using the “Parse JSON” flow action with the JSON schema downloaded from the event setup. That means there will be no automatically generated dynamic content available in the future but I think it is a better idea using a JSON parser than using the triggerBody() like I have shown in the article.
  • To follow any future changes to functionality, you can visit :
    https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/business-events/home-page

7 thoughts on “How to integrate D365FO with Microsoft Flow using the new Business Events

  1. Hi.

    Thanks you.
    i have a question, can i using the new Business Events in Production environment?
    i use PU27, and i check in system administrator -> Setup -> System parameter, i can’t see menu for Enabling Business Events. and i can’t use magic part in Production.

    Thanks.

    1. It is currently released for general availability (June 2019) and available from a dedicated Business Events Workspace or from the “System Administration / Setup / Business Events” menu.
      For PEAP (early access program) members using older PU version there is also an option to install it from a package in LCS software deployable packages.

  2. Hi Tayfun,

    Thanks for your post. I’m currently in a TIER 2 with PU28, and I can find the Business Events Catalogue menu, but I’m not able to find a menu to enable or disable these Business Events… Do you know where I can find it?

    Thanks again

    1. Ok, now I see what you mean, they have removed the old parameter screen with enabling and disabling button from non-production environments, and it comes disables by default..

      They tell now doing a database change by executing a SQL statement instead of clicking the button. You need to execute this SQL, and restart all services. I will update the blog with the information:

      UPDATE [dbo].[BUSINESSEVENTSPARAMETERS]
      SET [BATCHENABLED] = 1
      ,[PROCESSORTHREADS] = 1
      ,[ENDPOINTRETRYCOUNT] = 3
      ,[BUNDLESIZE] = 50
      ,[ENDPOINTSPEREVENT] = 10
      GO

Leave a Reply