Miklix

Calling AIF Document Services Directly from X++ in Dynamics AX 2012

Published: March 18, 2021 at 6:20:14 PM UTC

In this article, I explain how to call Application Integration Framework document services in Dynamics AX 2012 directly from X++ code, emulating both inbound and outbound calls, which can make it significantly easier to find and debug errors in AIF code.


The information in this post is based on Dynamics AX 2012 R3. It may or may not be valid for other versions.

I was recently helping a customer implement an Application Integration Framework (AIF) inbound port for creating customers based on data they were receiving from another system. As Dynamics AX already provides the CustCustomer document service, which implements the logic for this, we decided to keep it simple and use the standard solution.

However, it soon turned out that there were a lot of problems getting the external system to generate XML that Dynamics AX would accept. The XML schema generated by Dynamics AX is a quite complex one and it also appears there are few bugs in Dynamics AX that sometimes causes it to reject XML that is schema-valid according to other tools, so all in all, it proved to be less simple than I'd thought.

During the endeavor, I often struggled to figure out what exactly the problem was with certain XML files because the error messages provided by AIF are less than informative. It was also tedious, because I had to wait for the external system to send a new message over MSMQ and then again for AIF to pick up the message and process it before I could see an error.

I therefore investigated whether it's possible to call the service code directly with a local XML file for somewhat speedier testing and it turns out that it is - and not only that, it's really simple to do and actually provides a lot more meaningful error messages.

The example job below reads a local XML file and tries to use it with the AxdCustomer class (which is the document class used by the CustCustomer service) to create a customer. You can make similar jobs for all the other document classes, for example AxdSalesOrder, if you need.

static void CustomerCreate(Args _args)
{
    FileNameOpen fileName    = @'C:\\TestCustomerCreate.xml';
    AxdCustomer  customer;
    AifEntityKey key;
    #File
    ;

    new FileIoPermission(fileName, #IO_Read).assert();

    customer = new AxdCustomer();

    key = customer.create(  XmlDocument::newFile(fileName).xml(),
                            new AifEndpointActionPolicyInfo(),
                            new AifConstraintList());

    CodeAccessPermission::revertAssert();

    info('Done');
}

The AifEntityKey object returned by the customer.create() method (which corresponds to the "create" service operation in AIF) contains information about which customer was created, among other things the RecId of the created CustTable record.

If what you're trying to test is an Outbound port instead or if you just need an example of how the XML should look like on the Inbound port, you can also use the document class to export a customer to a file instead by calling the read() method (corresponding to the "read" service operation) instead, like so:

static void CustomerRead(Args _args)
{
    FileNameSave    fileName = @'C:\\TestCustomerRead.xml';
    Map             map      = new Map( Types::Integer,
                                        Types::Container);
    AxdCustomer     customer;
    AifEntityKey    key;
    XMLDocument     xmlDoc;
    XML             xml;
    AifPropertyBag  bag;
    #File
    ;

    map.insert(fieldNum(CustTable, AccountNum), ['123456']);
    key = new AifEntityKey();
    key.parmTableId(tableNum(CustTable));
    key.parmKeyDataMap(map);
    customer = new AxdCustomer();

    xml = customer.read(key,
                        null,
                        new AifEndpointActionPolicyInfo(),
                        new AifConstraintList(),
                        bag);

    new FileIoPermission(fileName, #IO_Write).assert();
    xmlDoc = XmlDocument::newXml(xml);
    xmlDoc.save(fileName);
    CodeAccessPermission::revertAssert();
    info('Done');
}

You should of course replace '123456' with the account number of the customer you wish to read.

Share on BlueskyShare on FacebookShare on LinkedInShare on TumblrShare on XShare on LinkedInPin on Pinterest

Mikkel Bang Christensen

About the Author

Mikkel Bang Christensen
Mikkel is the creator and owner of miklix.com. He has over 20 years experience as a professional computer programmer/software developer and is currently employed full-time for a large European IT corporation. When not blogging, he spends his spare time on a vast array of interests, hobbies, and activities, which may to some extent be reflected in the variety of topics covered on this website.