D365 Developer Series: X++ Chain of Command

Coding on a laptop

Using Chain of Command in X++

Chain of command has been available in Microsoft Dynamics 365 for a few years (since Platform Update 9), and we’re still seeing miscommunications around the topic. In this week’s blog, we will answer: What is it? How do I use it? When would I use it? What does it replace?

What is X++ chain of command in Dynamics 365?

In Microsoft Dynamics 365, Chain of Command (CoC) enables customization and extension of base Microsoft code. Microsoft’s base objects and code cannot be changed directly in D365, but CoC allows for the application’s capabilities to be extended.

The easiest way to explain chain of command is that next() is similarly used as super(). Anything before the next() call can be considered a pre-event handler and anything after it is considered a post-event handler.    

Please keep in mind that this is not creating a child class by the keyword extends. It is, however, allowing the developer to add business logic before or after existing method calls. It is called a chain because of the chain of events that occurs. Consider using chain of command on the update method for theSalesTable table. The chain would execute as follows: 

salesTable_Extension.update() before next() -> salesTable.update() -> salesTable_Extension.update() after next() 

When can I use X++ chain of command?

This can effectively eliminate the need to have two event handlers. For example, separate pre and post event handlers can be replaced by a single chain of command extension.  This can be used for both protected and public methods.

The Fine Print

Using chain of command for D365 requires a few things: 

  1. Decorating the class with [extensionOf(<Table, form, or class name>)] 
    1. You can extend tables, forms, and classes. In today’s example, we show you extending a table. Nothing really changes in extending forms and classes except what the ‘this’ keyword is in reference to. 
    2. You must use intrinsic functions tableStr(), formStr(), or classStr() to identify the object you’re extending. 
  2. Making your class final 
  3. Your method signature must match the method you’re extending  
  4. Optional parameters are not supported. 
    1. If the method you’re extending has optional parameters, leave off the defaulting.  
  5. The class name must end with _Extension
    1. This is by design for the compiler to recognize classes that are using chain of command for faster compile times. It will throw a compiler error if this is not present. 

As of the publishing date of this post, Microsoft states that the order in which extensions are called is to be considered random. What does this mean? If you have several extensions on the same method, then you cannot depend on the order of your call being first or last.

Example of pre and post event handler:

class salesTableEventHandler 
{ 
    const static str deliveryArgName = 'deliveryDate'; 
 
    [PreHandlerFor(tableStr(SalesTable), tableMethodStr(SalesTable, update))] 
    public static void SalesTable_Pre_update(XppPrePostArgs _args) 
    { 
        SalesTable salesTable = _args.getThis(); 
        // store the pre update value for later 
        _args.addArg(salesTableEventHandler::deliveryArgName, salesTable.DeliveryDate);  
    } 
 
    [PostHandlerFor(tableStr(SalesTable), tableMethodStr(SalesTable, update))] 
    public static void SalesTable_Post_update(XppPrePostArgs _args) 
    { 
        // get the stored value that we placed in args up above 
        SalesShippingDate origDeliveryDate = _args.getArg(salesTableEventHandler::deliveryArgName);  
        SalesTable salesTable = _args.getThis(); 
 
        if (salesTable.DeliveryDate != origDeliveryDate) 
        { 
            warning("The delivery date has been updated, make sure the new date is attainable."); 
        } 
    } 
} 
 

How to replace event handlers using chain of command:

[ExtensionOf(tableStr(SalesTable))] 
final class salesTable_Extension 
{ 
    // extending an existing method, so method signature matches 
    public void update() 
    { 
        SalesShippingDate origDeliveryDate = this.DeliveryDate; 
 
        // before the next is pre-update 
        next update(); 
        // after the next is post-update 
 
        if (this.DeliveryDate != origDeliveryDate) 
        { 
            warning("The delivery date has been updated, make sure the new date is attainable."); 
        } 
    } 
}  

In this blog, we have shown what chain of command is, how to use it, and what it effectively replaces in your programming needs to fit the needs of the business.  

Deep Expertise in Dynamics AX and D365 Development

enVista is dedicated to helping the Microsoft community by continuously sharing our in-depth knowledge of X++ and Microsoft Dynamics 365 development. If you are struggling with Dynamics AX or D365 development, contact us, and we will connect you with one of our in-house experts.  

Read our other topics in our D365 Developer Series: 

Data Contracts

SysLastValue in a Single Line

Extending Full-Text

Merging Financial Dimensions in D365 F&O

About the Author

Related Posts

Shopping Basket

Contact enVista

Thousands of clients across a variety of industries consider enVista an integral and important part of their business strategy. You should, too.
Notification Header
The leading news agency comes to your smartphone.  Download now.