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()
Hidden Treasures of Advanced Warehousing
Make the most of Microsoft Dynamics 365’s Advanced Warehousing module and gain insight into the hidden treasures to unlock value.
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:
- Decorating the class with [extensionOf(<Table, form, or class name>)]
- 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.
- You must use intrinsic functions tableStr(), formStr(), or classStr() to identify the object you’re extending.
- Making your class final
- Your method signature must match the method you’re extending
- Optional parameters are not supported.
- If the method you’re extending has optional parameters, leave off the defaulting.
- The class name must end with _Extension
- 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: