CLOUDCLIF – Blogs
  • Home
  • D365 F&O
  • Work Flows
  • Reports
  • Enterprise Portal
Category:

Uncategorized

Uncategorized

Event Handlers vs Chain of Command: The Real Decision Framework for 2026

by Muhammad Salman Siddiqui April 27, 2026

Reading time: ~9 minutes. 

Yesterday’s post argued that Chain of Command is usually the right tool for overriding F&O method logic. That was deliberately one-sided — you can’t teach a decision framework in one post. Today is the other side. Event handlers still have a clear, non-trivial place in every real F&O codebase, and choosing between the two is a daily call that no Microsoft Learn page walks you through. 

This post takes the short decision table from yesterday and stress-tests it — showing what each tool actually does, the sharp edges of each, and a scenario-by-scenario walkthrough that closes with a practical flowchart. 

If you haven’t read the CoC post yet: Chain of Command in D365 F&O 

The three kinds of “event handler” — they are not the same 

First, a clarification that saves hours of confusion later. When F&O developers say “event handler,” they mean one of three different things. Microsoft’s docs treat them as one family, but the decision calculus is different for each. 

1. Pre/Post handlers on methods — the [PreHandlerFor] and [PostHandlerFor] attributes. These wrap a specific method the same way CoC does, and they’re the direct alternative to CoC for method-level logic overrides. 

2. Data/form event handlers — [DataEventHandler] for table events (OnInserting, OnInserted, OnUpdating, and so on), and [FormEventHandler], [FormDataSourceEventHandler], [FormControlEventHandler] for their form equivalents. These are not method overrides. They are framework events — hooks that fire at specific lifecycle points, and CoC has no equivalent for most of them. 

3. Delegate subscribers — [SubscribesTo]. Microsoft (and well-designed ISV code) publishes delegate declarations at designated extension points. You subscribe to them with the SubscribesTo attribute. This is the cleanest, most forward-compatible form of extension — when a delegate exists for what you need, use it. 

Conflating these three is the source of most of the “I’ve heard CoC is better” confusion you’ll see in community threads. CoC only competes with category 1. For categories 2 and 3, there is no CoC alternative — handlers are the only game in town. 

Pre/Post handler anatomy — the version that actually competes with CoC 

A Pre or Post handler is a static method on a class, decorated with an attribute that binds it to a specific base method. The handler receives a single XppPrePostArgs parameter that carries this, the method arguments, and (for Post handlers) the return value. 

public static class MyTableEventHandler 
{ 
    [PostHandlerFor(tableStr(SalesTable), tableMethodStr(SalesTable, validateField))] 
    public static void SalesTable_Post_validateField(XppPrePostArgs _args) 
    { 
        SalesTable salesTable = _args.getThis(); 
        FieldId   fieldId    = _args.getArg("_fieldId"); 
        boolean   ret        = _args.getReturnValue(); 

        // additional validation here 
        _args.setReturnValue(ret); 
    } 
} 

That’s the pattern. Compared to the CoC version of the same override, note what’s happening: 

  • The handler is static. No instance. No access to protected members of the base class. 
  • Arguments are retrieved by string name — _args.getArg(“_fieldId”). If Microsoft later renames the parameter, the string still “compiles” but silently returns the wrong value (or null). This is the brittleness Microsoft warns about. 
  • Return value is read and written through the args object rather than by expression. Fine in Post; meaningless in Pre (you can setReturnValue in a Pre handler but it won’t influence the base method — the base method hasn’t run yet). 

Microsoft’s official documentation on this page (learn.microsoft.com/…/xpp-events) contains one of the most useful sentences in the entire F&O dev reference: “Pre and Post handlers can easily break as the result of added or removed parameters, changed parameter types, or because methods are no longer called, or called under different circumstances.” That’s Microsoft telling you, on their own reference page, that these handlers are inherently more fragile than CoC. Worth reading twice. 

Data event handlers — the non-negotiable use case for handlers 

Table events like OnInserting, OnInserted, OnUpdating, OnDeleting, OnDeleted, OnValidatedField don’t correspond to a specific X++ method you can wrap. They are framework events raised by the kernel around data operations, many of them implemented in the runtime rather than in X++ code. You cannot CoC-wrap them. A [DataEventHandler] subscription is the only extension mechanism. 

[DataEventHandler(tableStr(CustTable), DataEventType::Inserting)] 
public static void CustTable_onInserting(Common _sender, DataEventArgs _e) 
{ 
    CustTable custTable = _sender as CustTable; 
    // enrich the record before the insert actually runs 
} 

Same pattern for form controls (OnClicked, OnModified) and form data sources (OnInitialized, OnActivated, OnWritten). None of these have a CoC alternative. If someone tells you “always use CoC,” they’ve never had to react to a form-load event. 

Delegate subscribers — the cleanest extension point when one exists 

Microsoft publishes delegate declarations at many designated extension points throughout standard F&O code — particularly in posting, validation, and pricing flows. These are explicit invitations to extend behaviour cleanly. When a delegate exists for the scenario you need, it is almost always the right answer, ahead of both CoC and Pre/Post handlers. 

[SubscribesTo( 
    classStr(FMRentalCheckoutProcessor), 
    delegateStr(FMRentalCheckoutProcessor, RentalTransactionAboutToBeFinalizedEvent))] 

public static void RentalFinalizedEventHandler( 
    FMRental rentalRecord, Struct rentalConfirmation) 
{ 
    // respond to the published event 
} 

Two properties make delegates the safest choice when available. First, the method signature is enforced at compile time — a signature change in the base class fails your build instead of silently breaking your handler (unlike Pre/Post handlers). Second, delegates are Microsoft’s explicit contract that this is a supported extension point. They are less likely to move or be re-implemented in future updates than a randomly-chosen internal method. Docentric’s writeup on delegates has the best community-level explanation I’ve found of how return-value-carrying delegates work using EventHandlerResult — linked below. 

The capability comparison — side by side 

The short table from yesterday was a decision helper. Here’s the fuller capability grid — each row is something that either tool can or can’t do:

Capability Chain of Command Event Handler 
Access to protected members of the base class Yes No — the classic limitation 
Runs in the same transaction scope as the method Yes Different context — use carefully in ttsbegin blocks 
Can change return value Directly Yes, via args.setReturnValue() in Post handler 
Can change method parameters Directly on the arguments to next Indirectly, via args.getArg/setArg 
Works on framework/data events (OnInserting, OnModified, etc.) No Yes — this is what event handlers are for 
Works on Microsoft-published delegates No Yes, via [SubscribesTo] 
Call order is guaranteed No — random No — attribute-bound, no sequence guarantee 
Forced to invoke the base behaviour Yes (must call next, except on [Replaceable]) No — pre/post are strictly around the base, never instead of it 
Brittle to base-method signature changes Compile-time error if signature drifts Silent break: handler stops firing or args resolve wrong 

Four real scenarios — and the correct choice for each 

Scenario 1: “When a sales order is saved, push a message to an integration queue.” 

Right tool: Data event handler on SalesTable with DataEventType::Inserted. 

You’re reacting to an event, not overriding logic. You don’t need to change the insert behaviour, read protected fields, or influence a return value. A DataEventHandler is clearer and more maintainable than CoC on insert() or update() — and as of Platform Update 22, even the insert() CoC option is newer than the DataEventHandler pattern, which has been stable for years. ⚠ Be mindful that OnInserted fires after the insert commits; if you need pre-commit logic, use OnInserting. 

Scenario 2: “Validate a custom field on vendor master; reject the save if invalid.” 

Right tool: Chain of Command on VendTable.validateWrite(). 

You need to change the return value conditionally and you need access to the full record state including protected members. A Post handler on validateWrite would technically work via _args.setReturnValue(false), but CoC reads dramatically cleaner and is signature-stable. 

Scenario 3: “Show a warning to the user when a purchase order with a specific item is opened.” 

Right tool: Form data source event handler on OnInitialized (or a form control event handler depending on exact trigger). 

This is a framework event. There is no corresponding X++ method to wrap. CoC doesn’t apply. If you find yourself trying to CoC a form method here, step back — the form-nested CoC support in F&O covers data source and control methods but not every framework event. 

Scenario 4: “Add custom posting logic during sales invoice posting.” 

Right tool: check for a Microsoft-published delegate first. If found, use [SubscribesTo]. If none exists, CoC on the specific posting method. 

Posting flows are one area where Microsoft has published many delegates specifically to avoid people monkey-patching core posting logic. Spend ten minutes looking for one before you CoC a posting method — the delegate path is dramatically safer for upgrades. 

The decision flowchart, in prose 

A quick mental sequence for picking between CoC, Pre/Post handlers, and data/framework event handlers. Ask these questions in order and stop at the first “yes”. 

  1. Is there a Microsoft-published delegate for this scenario? → Use [SubscribesTo]. 
  1. Is the thing I want to react to a framework/data event (OnInserting, OnClicked, etc.), not a method body? → Use the appropriate event handler ([DataEventHandler], [FormControlEventHandler], etc.). 
  1. Do I need to override the logic of a specific public or protected method? → Default to CoC. 
  1. Is that method marked [Hookable(false)] or [Wrappable(false)] without a Wrappable(true) escape? → Fall back to a Pre or Post handler if the method is still subscribable, or redesign. 
  1. Do I need access to protected fields or methods of the base class? → CoC is the only option that gives you this cleanly. 
  1. Am I doing simple before-or-after logic that doesn’t need protected access, parameter modification, or transaction-scope-matching? → Either works; prefer Pre/Post only if you have a reason not to prefer CoC. 

3 tricky interview questions (with verified answers) 

As with yesterday’s post, each answer is grounded in named, verifiable sources (linked in the References section). 

Q1. A Pre handler and a CoC extension both wrap the same method. Which one runs first? 

Trick answer. Microsoft’s documentation is explicit that neither subscribers nor CoC extensions have a guaranteed sequence. The CoC docs say the system “randomly picks” among wrapped methods, and the events reference page states: “Since the binding between the publisher and subscribers is done through attributes, there’s no way of specifying the sequence in which subscribers are called.” Sertan Yaman’s empirical test, running mixed CoC + event handlers in a real environment, confirms the ordering is non-deterministic across both mechanisms and can vary between environments. Design for order-independence — assuming “pre handler runs first” is a bug waiting to happen. 

Q2. How do you pass state between a Pre handler and a Post handler on the same method? 

Both handlers are static methods on a handler class. Naïve option: a static field on that class — works for single-threaded cases but is fragile under concurrent calls. The cleaner, documented community technique (Ievgen’s AX blog, hosted on community.dynamics.com) uses XppPrePostArgs itself as the carrier: _args.addArg(‘myFlag’, value) in the Pre handler, _args.getArg(‘myFlag’) in the Post handler. The args collection is per-invocation, so state travels with the call rather than sitting in a shared field. ⚠ This relies on undocumented-but-stable behaviour of XppPrePostArgs; if this is critical path code, wrap it in a comment explaining what you’re doing and why. 

Q3. Can you subscribe a Pre/Post event handler to a protected or private method on a standard class? 

Directly, no. By default, only public methods are subscribable. Sertan Yaman documents a legacy workaround: overlayer the standard object and add a [Hookable(true)] attribute on the protected method. This is a relic of the overlayering era and is not recommended for modern F&O — overlayering on Microsoft packages is unsupported for most of the application, and even where technically possible it compromises upgrade safety. The correct modern answers are: (a) if you have access to protected members via CoC, use CoC — it sees protected members natively, which is one of its core advantages over Pre/Post; or (b) redesign to depend on a public method or a published delegate instead. If an interview candidate answers “just overlayer and add Hookable(true),” that’s a signal they learned F&O in the AX 2012 era and haven’t updated their mental model. 

What to actually do 

  1. Don’t treat “CoC vs event handlers” as one question. It’s three: (a) method override — CoC vs Pre/Post, (b) framework event — use the appropriate data/form event handler, (c) published extension point — use SubscribesTo. The wrong grouping is most of the confusion. 
  1. Default order of preference for reaction: SubscribesTo (if a delegate exists) → data/framework event handler (if the trigger is an event) → CoC (if you’re overriding method logic) → Pre/Post (only when CoC is blocked or unavailable). 
  1. Never rely on call order — between handlers, between CoC extensions, or between the two. Microsoft’s docs say it’s random; community tests confirm it; your bug reports will too if you ignore this. 
  1. Take Microsoft’s own warning seriously: Pre/Post handlers are more fragile than CoC. Prefer CoC for method overrides when both are feasible. 

References 

  • Microsoft Learn — Events and delegates (learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/dev-ref/xpp-events). Authoritative. Covers delegate syntax, SubscribesTo attribute, Pre/Post handler pattern, and the explicit fragility warning. Last updated February 2025. 
  • Microsoft Learn — Class extension: Method wrapping and Chain of Command (learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/extensibility/method-wrapping-coc). Covers CoC syntax and the Wrappable/Hookable attribute semantics. 
  • Sertan Yaman — D365 FO Extensibility Part 3: Event handlers and delegates (devblog.sertanyaman.com/2017/05/01/ax7-extensibility-part-3-event-handlers-and-delegates-hooks/). The PreHandlerFor / PostHandlerFor example code on InventTable, and the overlayer + [Hookable(true)] workaround for protected methods referenced in Q3. 
  • Docentric — Delegates and Event Handlers in D365FO (ax.docentric.com/delegates-and-event-handlers-in-d365fo/). Best community-level explanation of delegates, return-carrying EventHandlerResult pattern, and when to prefer SubscribesTo over other extension mechanisms. Updated February 2026. 
  • Ievgen’s AX blog — Trick to pass a value between Pre and Post event handler using XppPrePostArgs (community.dynamics.com). Source for the Q2 answer on carrying state between handlers via the args object. 
  • Mastering D365FO — Event Handlers in D365FO with Practical Examples (masteringd365fo.blogspot.com, April 2025). Practical Table, Form, and DataSource event handler patterns with current code samples. 

Next up in this series: The 5 X++ Extension Pitfalls I See on Almost Every Project. Shorter post, opinion voice, list format. 

April 27, 2026 0 comments
0 FacebookTwitterPinterestLinkedinWhatsappEmail
Uncategorized

Chain of Command in D365 F&O: A Practitioner’s Guide to When (and When Not) to Use It

by Muhammad Salman Siddiqui April 26, 2026

Reading time: ~8 minutes. 

Every D365 Finance & Operations developer writes Chain of Command code. Most write it wrong for the first six months. Not broken wrong — the code compiles and usually runs — but wrong in the ways that matter later: brittle under upgrades, confusing for the next consultant, silently slowing down batch processes, or wrapping methods that should never have been wrapped at all. 

This is a field guide, not a syntax tutorial. Microsoft’s documentation covers the syntax well (linked at the bottom). What the docs don’t cover is the decision — when CoC is the right tool, when it’s the wrong tool, and what tends to bite you in production. 

What CoC actually is (the one-minute version) 

Chain of Command is Microsoft’s supported way to inject custom logic into standard F&O methods without modifying Microsoft’s source code. You write an extension class, mark it with [ExtensionOf(…)], redeclare the method with the same signature, and call next to invoke the base implementation (and any other extensions in the chain). 

[ExtensionOf(tableStr(SalesTable))] 
final class SalesTable_MyExt_Extension 
{ 
    public void update() 
    { 
        SalesShippingDate origDeliveryDate = this.DeliveryDate; 
        next update();  // runs the base method + any other extensions 
        if (this.DeliveryDate != origDeliveryDate) 
        { 
            warning("Delivery date changed. Confirm the new date is attainable."); 
        } 
    } 
} 

The code before next runs as a pre-event. The code after next runs as a post-event. enVista’s writeup of the SalesTable.update() case is the cleanest worked example of this pattern I’ve come across. 

A few non-negotiable rules, straight from Microsoft: 

  • The extension class must be marked final and end in _Extension. 
  • The call to next must be at the top level of the method body. You cannot put it inside an if, a while, a for, or a logical expression. (As of Platform Update 21, wrapping next inside try/catch/finally is allowed.) 
  • The extension must be in a package that references the model where the base class lives. 
  • Default parameter values are declared on the base method, not repeated in the extension. If the base is salute(str message = “Hi”), your extension signature is salute(str message). 

These aren’t style suggestions. The compiler enforces them. 

The mental model: CoC is a wrapper, not a fork 

The single biggest conceptual mistake new F&O developers make is treating CoC like they’re subclassing the base method. They’re not. They’re wrapping it. The base method will still run. Any other extension in the chain will also run. And — this is the part that surprises people — the order in which extensions are called is not guaranteed. 

From Microsoft Learn, emphasis mine: “When the call to the next method occurs, the system randomly picks another method in the CoC. If no more wrapped methods exist, the system calls the original implementation.” 

What this means practically: if your logic depends on running before or after another ISV’s extension of the same method, you are in undefined territory. Don’t design that way. Design so your extension is order-independent. This is the rule that saves you the most pain at upgrade time. 

When CoC is the right tool 

Reach for CoC when: 

1. You need to modify the behavior of a specific public or protected method. The classic case: validate something extra on SalesLine.validateWrite(), or inject logic into CustTable.delete(). 

2. You need access to protected members of the base class. This is CoC’s real superpower over event handlers. Pre/post event handlers cannot see protected fields or methods. CoC can. If the logic you need to add requires inspecting this.someProtectedField, CoC is your only clean option. 

3. You need your logic to run in the same transaction scope as the base method. Event handlers run in a slightly different context; CoC runs inside the method’s own call frame. If you’re doing anything transactional — inserting child records, working with ttsbegin/ttscommit-dependent logic — CoC keeps you inside the right boundary. 

4. You want to conditionally change the return value or parameters. You can mutate the returned value after next, or adjust arguments before next. Event handlers can’t cleanly do this. 

5. Readability matters. A CoC extension sits next to the method it modifies and reads top-to-bottom. A pre/post event handler pair is two static methods somewhere else in your project, joined only by an attribute. For the developer who inherits your code two years from now, CoC is usually kinder.

When NOT to use CoC 

Here is where most of the production pain comes from. CoC is the wrong tool when: 

1. You need to react to a method you can’t or shouldn’t wrap. Methods marked [Hookable(false)] can’t be wrapped. Methods on extension classes themselves can’t yet be wrapped (Microsoft has said this is planned). Methods marked final without [Wrappable(true)] can’t be wrapped. In all these cases you’ll need a pre/post event handler, a delegate subscriber, or a redesign. 

2. You need multiple independent handlers. CoC lets multiple extensions wrap the same method, but each one must be in a separate extension class, and — again — the order is random. If what you actually have is three genuinely independent reactions to the same event (“log it,” “notify finance,” “push to the integration queue”), three event handlers express that intent more clearly than three CoC extensions competing on the same method. 

3. The method is performance-critical and called in a tight loop. Every wrapper adds a call frame. Usually this is irrelevant. But if you’re wrapping something like an inventory-settlement method that fires tens of thousands of times during month-end inventory close, even small per-call overhead compounds. ⚠ Benchmark before wrapping hot-path methods. A seemingly innocent CoC on a frequently-called table method can add minutes to a close run. 

4. You only need to react to a framework event, not override method logic. Form OnInitialized, data event OnInserting, menu item clicks — these are not method overrides, they’re events. Use event handlers. CoC doesn’t apply. 

5. You are tempted to not call next. There are narrow cases where Microsoft marks a method [Replaceable] and you are intentionally allowed to skip next. Outside those, if you find yourself wanting to skip next to “prevent” the base behavior, stop. You are fighting the framework. Upgrades will punish you. Find another approach — a different extension point, a different business process, or a conversation with the functional consultant about whether the requirement is real. 

The gotchas that bite in production 

A short list of issues that come up repeatedly on F&O projects: 

Form-nested CoC needs a separate extension class per nested concept. You can’t put a data source CoC and a control CoC in the same extension class. Each needs its own [ExtensionOf(formdatasourcestr(…))] or [ExtensionOf(formcontrolstr(…))] class. First-timers try to cram them together and the compiler silently ignores the wrong ones. 

The random-order behavior will eventually cause a bug you can’t reproduce locally. If two ISVs both extend the same method and one of them silently assumes it runs first, you’ll see a bug in one environment and not another. The fix is to design for order-independence. When you inherit someone else’s non-order-independent code, the only pragmatic options are to move the logic to a different extension point, or coordinate directly with the ISV. ⚠ This is the most painful CoC issue on multi-ISV projects. 

Kernel-implemented methods on tables and data entities weren’t wrappable before Platform Update 22. Before PU22, if you tried to wrap insert() or doInsert() through CoC you’d either get a compile error or silently different behavior depending on the platform version. Confirm your platform version if you’re relying on wrapping these. ⚠ 

Extensions must be on regular classes, not extensions of extensions. You can’t wrap a method defined inside another extension class. That capability is on Microsoft’s roadmap but not shipped as of this writing.

CoC vs Event Handlers: the decision in one table 

Situation Use 
Override the logic of a public/protected method CoC 
Need access to protected fields/methods of base CoC 
Need to change return value or parameters CoC 
Pure pre-or-post logging / notification Either — event handler often clearer 
Multiple independent reactions to same event Event handlers 
Framework event (form init, data event, menu click) Event handler 
Method is [Hookable(false)] or sealed final Event handler, if available, else redesign 
A Microsoft-provided delegate exists Delegate subscriber 

What to actually do 

If you’re new to F&O development and learning CoC right now, the shortest honest advice: 

  1. Default to CoC for method-logic overrides. It’s the pattern Microsoft is investing in, it reads better, and it’s more powerful. 
  1. Default to event handlers for framework events and for “I just want to react when X happens” logic. 
  1. Always assume your extension is not the only one on a method. Write for order-independence. 
  1. Before wrapping a hot-path method, benchmark. A fraction-of-a-millisecond overhead in an inventory close is a real problem. 
  1. Read the Microsoft Learn page on method wrapping all the way through, including the restrictions section. Most CoC bugs trace back to ignoring the rules on next. 

References 

  • Microsoft Learn — Class extension: Method wrapping and Chain of Command (learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/extensibility/method-wrapping-coc). Authoritative reference. Covers syntax, restrictions, wrappable/hookable attributes, form-nested extensions, and platform update history. 
  • Sertan Yaman — AX7 (D365) Chain of Command with Examples (devblog.sertanyaman.com/2017/11/15/ax7-d365-chain-of-command-with-example/). The clearest working demonstration of CoC’s random-order behavior and how it interacts with pre/post event handlers on the same method. 
  • enVista — D365 Development: X++ Language Chain of Command Examples (envistacorp.com/blog/x-language-chain-of-command). Good SalesTable.update() worked example used as inspiration for the snippet above. 
  • Dynamics Edge — Chain of Command D365 Fundamentals Training (dynamicsedge.com/chain-of-command-d365-fundamentals-training-aug-2025/). Useful for the Platform Update 21 (try/catch/finally around next) and Platform Update 22 (wrapping kernel-implemented table methods) enhancements. 
  • Stoneridge Software — Using the Chain of Command feature in X++ (stoneridgesoftware.com/using-the-new-chain-of-command-feature-in-x/). Introductory-level overview; good first read for developers new to the concept. 
  • Dynamics 365 Musings — Chain Of Command In D365 Fundamentals (dynamics365musings.com/chain-of-command-in-d365/). Developer perspective on readability of CoC vs event handlers. 
  • Docentric — How to Skip Next in CoC of a Method in X++ (ax.docentric.com/how-to-skip-next-in-coc-of-a-method-in-xpp/). Original writeup of the try/catch with Exception::UpdateConflict hack. Explicitly warns the loophole may close in future updates. 
  • Flixelius — How to skip ‘Next’ in a CoC Method in X++ (flixelius.de). Worked example of the skip-next hack on CustTable.validateWrite(), including the transaction-exception reasoning. 
  • Microsoft Learn — X++ exception handling (learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/dev-ref/xpp-exceptions). Explains why Exception::UpdateConflict and DuplicateKeyException behave differently from Exception::Error inside transactions — the foundation of why the skip-next hack works. 

3 tricky interview questions (with verified answers) 

These come up in real F&O developer interviews. Each answer is grounded in Microsoft’s own documentation and named community sources — no guesswork. Sources are linked in the References. 

Q1. Can you skip the next call in a CoC extension? 

Short answer: yes, in three different ways, with very different consequences. 

1. The sanctioned way — if the base method is marked [Replaceable], the compiler does not require you to call next. Microsoft explicitly designed this attribute so that extenders can fully override the base logic. This is the only clean, upgrade-safe way to skip next. Even here, the recommended practice is to skip conditionally — you still want the base behaviour in most cases. 

2. The compiler-enforced default — for methods not marked [Replaceable], the compiler forces next at the top level of the method body. You cannot place it inside an if, while, for, do-while, or a logical expression. A return cannot precede it. This is by design. 

3. The known community hack (Platform Update 21+) — place next inside a try/catch block where the catch is only entered when a specific exception is thrown. The compiler accepts this because PU21 officially allows next inside try/catch/finally. The exception of choice is Exception::UpdateConflict — not Exception::Error — because UpdateConflict and DuplicateKeyException are two of the very few exception types that can be caught inside a ttsBegin/ttsCommit transaction block. Regular Exception::Error bubbles out of transactions and can’t be caught locally. 

⚠ Important: the hack in option 3 is a loophole, not a feature. Docentric, who originally published it, explicitly warns not to rely on it — Microsoft could change the behaviour of next or exception handling in any future platform update. Use it only when the method is truly unwrappable any other way, and document why you did it. 

Q2. If two ISVs both extend the same method using CoC, whose extension runs first? 

Trick question. The answer is: undefined. Microsoft’s documentation is explicit on this: 

“The system randomly runs one of these methods. When the call to the next method occurs, the system randomly picks another method in the CoC. If no more wrapped methods exist, the system calls the original implementation.” 

You cannot design for execution order. Writing extensions that silently depend on running before or after another party’s extension is one of the most painful bugs to find, because the failure will reproduce in one environment and not another. 

The three real options when order matters: 

  • Redesign the extension to be order-independent. This is almost always possible and is the right answer in interviews. 
  • Move the logic to a different extension point where order is controlled — a Microsoft-provided delegate, or a pre/post event handler where you at least know the phase. 
  • Coordinate directly with the other ISV to split responsibility cleanly. Rare, but sometimes the only path. 

Q3. What’s the difference between [Hookable(false)] and [Wrappable(false)]? 

This one trips up experienced developers. The two attributes look similar and they are not the same. 

[Hookable(false)] — blocks both pre/post event handlers and CoC wrapping. The method is completely sealed for extension. No way in. 

[Wrappable(false)] — blocks CoC wrapping only. Event handlers still work. This is a finer-grained lock. 

[Wrappable(true)] — the inverse escape hatch. Applied to a final method, it overrides the default “final methods can’t be wrapped” rule and allows CoC. 

[Hookable(true)] — and here is the trap. This attribute only applies to pre/post handlers. It does not influence whether CoC wrapping is allowed. A senior developer who assumes [Hookable(true)] makes a method CoC-wrappable will be wrong. 

All four of these are explicitly documented on the Microsoft Learn page cited below. 

Next up in this series: Event Handlers vs Chain of Command — The Real Decision Framework for 2026. We’ll take the decision table above and stress-test it against real project scenarios. 

April 26, 2026 0 comments
0 FacebookTwitterPinterestLinkedinWhatsappEmail

Recent Posts

  • Delegates in X++: The Underused Pattern for Clean Extensibility 
  • Table Extensions vs CoC on Tables: Picking the Right Tool for Adding Fields and Logic 
  • Form Extensions in D365 F&O: Data Sources, Controls, and the Gotchas Nobody Warns You About 
  • The 5 X++ Extension Pitfalls I See on Almost Every D365 F&O Project 
  • Event Handlers vs Chain of Command: The Real Decision Framework for 2026

Recent Comments

No comments to show.

About Me

About Me

Writer & Reader

Muhammad Salman Siddiqui

Technical Delivery Lead for Dynamics 365 Finance & Operations | Solution Architect

A consistent, meritorious and motivated professional looking forward to a challenging career in an environment that brings the best out of people while developing them personally and professionally.

read more

Keep in touch

Linkedin Email

Recent Posts

  • Delegates in X++: The Underused Pattern for Clean Extensibility 

    April 30, 2026
  • Table Extensions vs CoC on Tables: Picking the Right Tool for Adding Fields and Logic 

    April 30, 2026
  • Form Extensions in D365 F&O: Data Sources, Controls, and the Gotchas Nobody Warns You About 

    April 29, 2026
  • The 5 X++ Extension Pitfalls I See on Almost Every D365 F&O Project 

    April 27, 2026
  • Event Handlers vs Chain of Command: The Real Decision Framework for 2026

    April 27, 2026

Categories

  • D365 F&O (5)
  • Uncategorized (2)

About me

banner

Muhammad Salman Siddiqui

Technical Delivery Lead for Dynamics 365 Finance & Operations | Solution Architect

A consistent, meritorious and motivated professional looking forward to a challenging career in an environment that brings the best out of people while developing them personally and professionally.

read more

Popular Posts

  • 1

    Designing a Scalable Multi-Source Order Processing Cycle in Dynamics 365 Finance & Operations

    February 16, 2026
  • Chain of Command in D365 F&O: A Practitioner’s Guide to When (and When Not) to Use It

    April 26, 2026
  • Event Handlers vs Chain of Command: The Real Decision Framework for 2026

    April 27, 2026
  • Linkedin

@2026 - All Right Reserved. Designed and Developed by CLOUDCLIF


Back To Top
CLOUDCLIF – Blogs
  • Home
  • D365 F&O
  • Work Flows
  • Reports
  • Enterprise Portal