As of platform update 9 of Dynamics AX for Operations, we have a new extension possibility called chain of command. Now we are able to add pre and post functionality to extensible methods in a much easier and readable manner than the previously used event handlers, also we are now able to access protected methods and variables directly in the extended class without problems.

Now let’s check how it works with an example. Create two classes, one is the base class of the other and add a method we want to extend called ‘testMe’. Add infolog calls inside the method to track the execution :

class COCBaseClass
{
void new(){}
protected void testMe()
{
info("base class call");
}
public void runTest()
{
    this.testMe();
}
}

class COCChildClass extends COCBaseClassclass
{
protected void testMe()
{
    info("child class before super");
    super();
    info("child class after super");
}
}

Create a new model, add reference for the class model we created above, and add an extension class for our child class.

[ExtensionOf(classStr(COCChildClass))]
final class COCChildClassCOCExt_Extension
{
protected void testMe()
{
    info("Extension 1 before next call");
    next testMe()
    info("Extension 1 after next call");
}
}

The method we added here is the new chain of command definition. We use exactly the same notation as the original method we are extending and add a mandatory “next” keyword to the call which will wrap our extension code around the extended method. This next keyword separates the pre and post parts of our extension and mandatory to be called inside the chain of command method. Next call cannot be placed in any kind of program block like if() block or while block. When you call next(), it checks for other extensions in the queue and runs them in random order, lastly running the base code.

Sounds complicated enough? Let’s run our example by calling runTest method and see the outcome (Note : All tests in this blog are executed in Update11 version) :

Capture1

As you see, it runs nearly the same as pre and post handlers, pre being before the next call and post after it. The advantage of chain of command is you can share the same method variables in the pre and post (before/after next() call) or share the same tts block inside your COC method. COC also supports return value and parameter modification of the extended method in a much more readable manner. Extending a method with return value and parameters in COC is like below :

class COCBaseClass
{
protected int returnMe(int _me)
{
return _me;
}
}
class COCChildClass extends COCBaseClass
{
protected int returnMe(int _me)
{
return super(_me);
}
}
[ExtensionOf(classStr(COCChildClass))]
final class COCChildClassCOCExt_Extension
{
protected int returnMe(int _me)
{
   int ret;
   ret = next returnMe(_me);
   return ret;
}
}

Now let’s examine some more complex scenarios. Let’s create some other models and add some more chain of command extensions to our testMe method. Here are our two new extension classes in two new models :

[ExtensionOf(classStr(COCChildClass))]
final class COCChildClassCOCExt2_Extension
{
protected void testMe()
{
    info("Extension 2 before next call");
    next testMe()
    info("Extension 2 after next call");
}
}
[ExtensionOf(classStr(COCChildClass))]
final class COCChildClassCOCExt3_Extension
{
protected void testMe()
{
    info("Extension 3 before next call");
    next testMe()
    info("Extension 3 after next call");
}
}

When we run our code this time, it creates the following result, calling all before next () parts of chain of command extension methods, calling the base method, then calling code after the next() calls. :

Capture2

Realize that, as described by Microsoft, the chain of command extension methods are called in random order, as 3,1 and 2. And the base method is always called in between the next calls. However the code blocks after next() calls are always executed in a mirrored order of the preceding calls, as 2,1 and 3.

Now let’s add some pre and post eventhandlers and call them together with our chain of command methods to test how they relate to each other. I will add the eventhandlers to our new extension classes. Remember to make our protected ‘testMe’ method hookable by adding [HookableAttribute(true)] on top of the method before adding your eventhandlers:


[ExtensionOf(classStr(COCChildClass))]
final class COCChildClassCOCExt2_Extension
{
[PreHandlerFor(classStr(COCChildClass), methodStr(COCChildClass, testMe))]
public static void COCChildClass_Pre_testMe(XppPrePostArgs args)
{
info("Extension 2 pre-eventhandler");
}

[PostHandlerFor(classStr(COCChildClass), methodStr(COCChildClass, testMe))]
public static void COCChildClass_Post_testMe(XppPrePostArgs args)
{
info("Extension 2 post-eventhandler");
}
}

Repeat the same for extension class 3, and run the test again to see the result :

Capture3

As you see the pre and post eventhandlers run after and before the chain of command calls. So chain of command wraps the base method, and its pre and post eventhandlers all together. Just as chain of command, the eventhandler methods are also called in a random order, and not mirrored on pre and post like the chain of command calls.

You can also change the return value and the parameters of the base method call using chain of command. However you should be really careful with the fact that the execution order is random and the return value set by the latest COC post call is returned on the chain. Now lets change our ‘returnMe’ method to echo the parameter on infolog and add the following chain of command methods to our 3 extension classes for returnMe method manipulating the parameter and return value before and after next call :

 protected int returnMe(int _me)
{
info(strfmt("Base class value : %1", _me));
return _me;
}
protected int returnMe(int _me)
{
 int ret;

_me = 1;

ret = next returnMe(_me);

ret = 11;

return ret;
}

Then we test the code by running it with a parameter of ’99’ and displaying the return value in the runnable class:

public static void main(Args _args)
{
COCChildClass test = new COCChildClass();

//test.runTest();
info(int2str(test.runReturnMe(99)));
}

Capture4

 

The parameter has changed to 1 and the return value exited with the extension on class2.

Hope you enjoyed reading. You can download the test projects of the blog from the link below:

https://github.com/sertanyaman/SertanDevAXExamples/blob/master/COCTest.zip

 

2 thoughts on “AX7 (D365) Chain of command with examples

  1. Hi Tayfun,

    I have a unique scenario, Suppose a child class is calling a parent class method and a COC is implemented upon the parent class’s method. Suppose their are several other child classes who have called this parent class method, in this case, is their any way in the implemented COC to find who is caller , in other words which is the particular child class calling implemented COC..??

    1. You can try the “is” keyword. Do not directly use ‘this’ ( like if(this is ChildClass) ) but declare and cast ‘this’ keyword in your COC method into your parent class, like : ParentClass parent = this; Then use ‘is’ keyword to check which child class is the current caller like : if(parent is ChildClass1){} for ex.

Leave a Reply