Chain of Commands & Class Extension: Dynamics 365 For Finance & Operations

1. Introduction

A notable change from Microsoft Dynamics AX 2012 is that Microsoft Dynamics 365 for Finance and Operations does not include a rich-client application (ax32.exe). From a development perspective, this means that the Microsoft Dynamics AX 2012 development environment, MorphX, is no longer used. In its place, the application development is carried out exclusively in Visual Studio.

The development tools support all of the development tasks, including debugging and local testing scenarios. A primary goal of the development experience is to keep familiar Microsoft Dynamics AX 2012 concepts, and seamlessly adapt them to the Visual Studio framework and paradigms.

As a next challenge, the development of Ax is not as straightforward as it happened to be in its previous versions. For customizations of standard/existing code, you cannot override a method by opening and nevigate to the concerned node(class method/table method/form method) and choose from override able set of methods. This prevents you to write/debug any code as you wish, limiting your codes to the mere selection of adding event handlers.


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. This enables you to call/use protected members and methods without making them hookable and using pre/post event handlers.


From PU9, the usage of extension classes (also known as class augmentation) is introduced to let developers to wrap logic around methods defined in a base class: a process which was forbidden for so long in all the previous platform updates of D365. This lets you extend the logic of public and protected methods without the need to use event handlers. When you wrap a method, you can also access other public and protected methods and variables of the class. As a result of this, you can start transactions and easily manage state variables associated with your class.


D365 For Finance & Operations with PU >= 9

VS 2015

Before you begin: revisiting the concepts


In D365, we have packages for deployment purpose. A package may contain one or more models. In addition to elements of the model, this also includes model metadata which is the description data that define the properties and behavior of the model. Also a package can be exported to a file which can then be deployed into a staging or production environment. In other words, you can say package is an independent set of layers and models. It's also a set of folders that consists of XML files representing the elements in the system. In this way, a package can be viewed as a mini/pseudo model store. Physically package translates directly to unit of compilation which is an assembly or DLL file. Packages can reference other packages that is similar to how .NET assemblies can reference each other.


Unlike AX2012, In DAX365, creating a model is mandatory thing for any sort of customization. A particular model can contain multiple Visual Studio projects. Therefore you can say it is a collection of projects and a single project can have all or subset of elements from originating model. However, association of a project is only with a single model. It is basically a unit of development/customization. Metadata for models is stored locally on an XML file called a descriptor XML.

Hookable attribute

Hookable methods are non-abstract methods that are either public or have been attributed with Hookable(true).

[HookableAttribute(true)] protected void loadModule() { NumberSeqDatatype dataType = NumberSeqDatatype::construct(); // Store id (scope is global) dataType.parmDatatypeId(extendedTypeNum(RetailStoreId)); dataType.parmReferenceHelp(literalStr( & quot; @RET3015 & quot;)); dataType.parmWizardIsContinuous(false); dataType.parmWizardIsManual(NoYes::No); dataType.parmWizardIsChangeDownAllowed(NoYes::No); dataType.parmWizardIsChangeUpAllowed(NoYes::No); dataType.parmSortField(1); this.create(dataType); }

Chain of Command Example

Class Vehicle { real noOfWheels(int arg) {…} }

Now we can extend the functionality of no Of Wheels using an extensjon class by re-instigating the same name to add pre-and post-logic to it.


class truck { real noOfWheels (int arg) { var ret = next noOfWheels (arg + 5); return ret; } }

Wrapping no Of Wheels and the required use of the next keyword creates a Chain of Command (CoC) for the method. It results in the following:

Vehicle v = new Vehicle(); Print v.noOfWheels(2);

The system will find any method that wraps studentAge. It randomly executes one of these methods (say, noOfWheels of the truck class). When the call to next no Of Wheels() occurs, the system will randomly take up another method in the Chain of Command or call the original definition if nothing exists.


Public and protected methods

Protected or public methods of classes, tables, or forms can be wrapped by using an extension class that augments that class, table, or form. The wrapper method must have the same signature pattern as that of the base method.

i.e. if Class A and ClassB are augmenting Class X and if you have defined a method on Class A as method m1, then this method m1 won’t be available to be wrapped in class B.

Also if Class Root(the base class) has a method m1(int x, int y), then while augmenting it in class A, you cannot write a method m1(realx, real y)

Default parameters

You can wrap methods that have default parameters, by class extension. However, the method signature in the wrapper method must not include the default value of the parameter.

For example, the following simple class has a method that has a default parameter.

class vendBalance { Public void amountMST(VendAccount _vendAccount = ‘’) {} }

In this case, the wrapper method must resemble the following example.

[ExtensionOf(classtr(Person))] final class vendBalance_Extension { Public void amountMST(VendAccount _vendAccount) {} }

Notice that in vendValance_Extension extension class, the amountMST method doesn't include the default value of the message parameter.

Accessing protected members from extension classes

As of PU9, you can acces protected members from extension classes. These protected members include fields and methods. Note that this support isn't specific to wrapping methods but applies all the methods in the class extension. Therefore, class extensions are more powerful than they were before.

The Hookable attribute

If a method is explicitly marked as [Hookable(false)], the method can't be wrapped in an extension class. In the following example, anyMethod can't be wrapped in a class that augments anyClass1.


Kernel methods cannot be wrapped:

Kernel classes aren't X++ classes. Instead, they are classes that are defined in the kernel of the Microsoft Dynamics 365 Unified Operations platform. Even though extension classes are supported for kernel classes, method wrapping isn't supported for methods of kernel classes. In other words, if you want to wrap a method, the base method must be an X++ method.

Netsed class methods cannot be wrapped :

The concept of nested classes in X++ applies to forms for overriding data source methods and form control methods. Methods in nested classes can't be wrapped in class extensions.

Conclusion :

Above the innovative information about chain commands & class extension feature In Dynamics 365 for finance & operations described give you completely. For more information about our Microsoft dynamics AX consultants India please contact us.

  • img
  • img
  • img
  • img
  • img
  • img
  • img
  • img
  • img
  • img
  • img
  • img
  • img
  • img
  • img
  • img
  • img