Chain of command and method wrapping
Chain of command
Chain of command refers to the hierarchical structure within a team or organization that dictates how decisions and information flow. It starts with top-level management, such as project managers or team leaders, and it moves down to individual developers. This structure ensures that everyone knows whom to report to and who is responsible for making decisions. This clear line of authority helps maintain order, streamline communication, and ensure that workers complete tasks efficiently and correctly.
Chain of command as a design pattern
Chain of Command (CoC) is a design pattern where a series of receivers handles a request. The receivers use an extension class to wrap protected or public methods of classes, tables, data entities, and forms. You should be aware of some restrictions when wrapping methods:
The wrapper method must have the same signature as the base method.
When you augment form classes, you can wrap only the root-level methods, not defined methods in nested classes.
Extend logic with wrappers
You can wrap logic around methods that are defined in the base class that you're augmenting. You can also extend the logic of public and protected methods without needing to use event handlers.
In most cases where you need to change or extend the logic of an existing method, you should prefer Chain of Command (CoC) over pre- and post-method event handlers or custom delegates. CoC keeps your extension physically and conceptually close to the base implementation (easier to discover and maintain), makes it easier to understand how a method is extended, and takes full advantage of the extension framework that was introduced to avoid overlayering.
When wrapping a method, you can access public and protected methods and variables of the base class. By using a wrapper around a method and the next keyword, you can create a chain of command.
Wrapper methods in an extension class must always call next so that the system always calls the next method in the chain and the original implementation.
Method wrapping
Method wrapping is a technique in programming where one function (the wrapper) calls another function. The main purpose of the wrapper is to simplify or extend the functionality of the original function without modifying its code. This technique can be useful for adding extra features, such as logging, error handling, or input validation. For example, if you have a function that performs a complex calculation, you might create a wrapper function that first checks if the input values are valid before it calls the original function.
Declare a method
Method declarations consist of a signature and a body. The signature contains the following features:
Access modifiers – Use to dictate what code is allowed to access, such as public, private, and internal protected.
Modifiers – This feature isn't required, but it helps the compiler determine how to treat the method.
Return type – Every method declaration must have a return type. If the method isn't designed to return any value, you must use void as the return type.
Arguments – This feature isn't required in method declarations, but they're useful for changing how a method behaves.
Wrap public and protected methods
You can wrap protected or public methods of classes, tables, data entities, or forms by using an extension class. The wrapper method must have the same signature as the base method.
When you augment form classes, you can wrap only root-level methods. You can't wrap defined methods in nested classes.
Currently, you can wrap only methods that are defined in regular classes. You can't wrap methods that are defined in extension classes by augmenting the extension classes. This capability is planned for a future update.
Wrap instance and static methods
You can extend instance and static methods by using extension classes, which offers flexibility in customizing functionality. When you're wrapping a static method, the method in the extension class must include the static keyword. Instance methods, often called object methods, are tied to specific objects that are created from a class and require instantiation before use. These methods can access instance-level and static-level states.
In contrast, static methods, also known as class methods, don't require instantiation and can only access the static state. For example, you can invoke the Main method, a common static method, directly from a menu option.
Instance and static methods consist of a signature and a body. The signature defines the method's name, return type (void or otherwise), modifiers, and parameters, while the body contains variable declarations, extra method calls, and executable statements. This clear structure ensures that methods are well-defined, maintainable, and extensible in your codebase.
Chain of Command and method wrapping
The following scenario illustrates use of the Chain of Command (CoC) functionality and method wrapping in finance and operations apps by using an extension class. The example demonstrates how to extend the functionality of a base class method without modifying its original implementation.
Scenario
You have a class called SalesLine with a calcLineAmount() method that calculates the amount for a sales line. You want to extend this method to add a custom discount calculation, but you want to ensure that the base method logic is still implemented.
Base Class
Extension class with method wrapping
First, you create an extension class to wrap the calcLineAmount method by using the Chain of Command (CoC) functionality.
public class SalesLine
{
public Amount calcLineAmount()
{
// Original logic for calculating the line amount
return this.Qty * this.Price;
}
}
[ExtensionOf(classStr(SalesLine))]
final class mySalesLine_Extension
{
public Amount calcLineAmount()
{
// Call the base implementation
Amount baseAmount = next calcLineAmount();
// Add custom logic (e.g., apply an additional discount)
Amount discount = baseAmount * 0.10; // Apply 10% discount
Amount finalAmount = baseAmount - discount;
return finalAmount;
}
}
Key points to consider for this scenario:
Call to next - The next keyword ensures that the original implementation of calcLineAmount() in the base class is run before you apply custom logic.
Extending logic - After calling the base method, you apply extra custom logic (such as, calculating a discount).
Signature match - The method in the extension class has the same signature (calcLineAmount) as the method in the base class.
What happens at runtime
During runtime, when calcLineAmount() is called on an instance of SalesLine, the runtime system:
Runs the logic in the extension class (SalesLine_Extension).
Calls the base method (next calcLineAmount()).
Combines the logic from both methods by providing extended functionality.
Reasons to use Chain of Command
The reasons for using the Chain of Command (CoC) functionality include:
Non-intrusive - No need to modify the base class code.
Safer Upgrades - Base class updates won't overwrite or conflict with your customizations.
Extensibility - Multiple extensions can wrap the same method, forming a chain.
Note
When multiple extensions wrap the same method in finance and operations apps, the developer can't explicitly define the implementation order of these extensions. This behavior is crucial to understand when you're working with Chain of Command (CoC).
Best practice: Prefer Chain of Command before event handlers and delegates
When you extend existing business logic in Dynamics 365 Finance and Operations apps, use the following order of preference:
Chain of Command (CoC) – first choice for extending method logic
Event handlers – when you need to react to events that CoC can’t handle
Delegates + event handlers – when you want to raise extensibility points for other code to subscribe to
Why CoC is the safer first choice for method logic
CoC is usually the preferred and more maintainable option for extending method logic when the base method is wrappable.
Closer to the base code
- The extension method has the same signature as the base method and sits in an extension class that clearly targets that specific class and method. This makes the extension easier to discover and maintain.
Direct access to state
- CoC gives you access to public and protected members and internal state of the base class, which is harder or more verbose to reach from generic event handlers.
Readable execution flow
- The next call shows exactly when the base implementation runs, so the order of “before / base / after” logic is explicit in a single method body instead of being spread across multiple handlers.
Fewer surprises with pre/post-method handlers
- Community guidance recommends avoiding pre- and post-method event handlers when CoC is available, because CoC provides a more predictable and maintainable extension pattern for method-level customizations.
Because of these advantages, CoC is the recommended best practice for extending business logic in methods that are wrappable.
When to use event handlers instead
Event handlers still have an important role, but their sweet spot is different from CoC. Use event handlers when:
You need to react to modeled events (for example OnCreated, OnValidated, or table and form data events).
You want to centralize cross-cutting logic, such as logging or auditing several controls or tables from a single handler class.
You’re subscribing to delegates that are raised by the platform or by other customizations. CoC cannot subscribe to delegates; you must handle them via event handlers.
Event handlers are therefore ideal for:
UI events (form controls, field modifications, button clicks)
Table and data events (insert/update/delete handlers)
Handlers for delegates that broadcast business events
When to use delegates and event handlers
Delegates define extension points that other code can subscribe to; event handlers are the subscribers. They’re a good fit when you:
Want to expose a customization hook from your own code for other models or solutions.
Need to decouple the publisher from the subscriber so that the publisher doesn’t know who is listening.
Must allow multiple subscribers to respond to the same event (for example, multiple solutions reacting to a workflow or document-processing event).
Use delegates and event handlers when you’re raising or consuming events, not when you simply need to extend the implementation of a single wrappable method. For that, CoC remains the preferred approach.
Additions — practical rules & gotchas
Wrappable / Replaceable / Hookable attributes: Not every method is wrappable by default. Microsoft’s attributes control extensibility: Wrappable, Replaceable, and Hookable. Wrappable(false) prevents CoC wrapping; Replaceable allows skipping next (use carefully). Read the attributes guidance before deciding to change the base.
next requirement: For normal wrappable methods extenders must call next (you cannot skip the base logic) unless the method is explicitly marked Replaceable. If a method is Replaceable, extenders can conditionally skip execution — only use this where skipping is safe and documented.
Private & final methods: Private methods are not wrappable. Public/protected methods marked final are not wrappable unless the owner explicitly enables it (wrappable attribute). Always check the base method attributes.
Performance: Marking many methods as hookable/wrappable adds small IL overhead. For performance-critical hot paths, prefer avoiding unnecessary hookable/wrappable attributes.
Avoid deep CoC chains: Multiple CoC layers can make debugging harder (deep call stacks). Keep each extension focused and small; prefer small, well-named extension methods.
Testing: Unit and integration tests should cover both the base behavior and extension scenarios (including multiple subscribers to delegates and the order of CoC extensions where relevant).
Quick decision guide
Use CoC when you need to extend/modify a public or protected method, and you want logic kept tightly coupled to the method.
Use event handlers when responding to model events, table/form actions, or when you need a single handler to handle multiple events.
Use delegates when creating public extensibility hooks that others will subscribe to.
Summary decision guide
Use CoC when
You need to extend or modify the logic of a public or protected method in a class, table, data entity, or form.
You want to run code before and/or after the base method and keep the logic closely tied to that method.
Use event handlers when
You need to respond to modeled events or delegates (UI events, table events, system delegates).
You want a single handler to respond to multiple events or to add/remove handlers at runtime.
Use delegates when
- You’re defining new extensibility points in your own code and want other solutions to plug in via event handlers.