{"id":1409,"date":"2026-04-27T05:34:36","date_gmt":"2026-04-27T05:34:36","guid":{"rendered":"https:\/\/cloudclif.com\/blogs\/?p=1409"},"modified":"2026-04-27T05:40:34","modified_gmt":"2026-04-27T05:40:34","slug":"event-handlers-vs-chain-of-command-the-real-decision-framework-for-2026","status":"publish","type":"post","link":"https:\/\/cloudclif.com\/blogs\/2026\/04\/27\/event-handlers-vs-chain-of-command-the-real-decision-framework-for-2026\/","title":{"rendered":"Event Handlers vs Chain of Command: The Real Decision Framework for 2026"},"content":{"rendered":"\n<p><em>Reading time: ~9 minutes.<\/em>\u00a0<\/p>\n\n\n\n<p>Yesterday&#8217;s post argued that Chain of Command is usually the right tool for overriding F&amp;O method logic. That was deliberately one-sided \u2014 you&nbsp;can&#8217;t&nbsp;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&amp;O&nbsp;codebase, and&nbsp;choosing between the two is a daily call that no Microsoft Learn page walks you through.&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img fetchpriority=\"high\" decoding=\"async\" width=\"672\" height=\"340\" src=\"https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/post-2-img-1.png\" alt=\"\" class=\"wp-image-1414\" style=\"width:741px;height:auto\" srcset=\"https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/post-2-img-1.png 672w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/post-2-img-1-300x152.png 300w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/post-2-img-1-585x296.png 585w\" sizes=\"(max-width: 672px) 100vw, 672px\" \/><\/figure>\n\n\n\n<p>This post takes the short decision table from&nbsp;yesterday&nbsp;and stress-tests it \u2014 showing what each tool&nbsp;actually does, the sharp edges of each, and a scenario-by-scenario walkthrough that closes with a practical flowchart.&nbsp;<\/p>\n\n\n\n<p>If you\u00a0haven&#8217;t\u00a0read the CoC post yet:\u00a0<a href=\"https:\/\/cloudclif.com\/blogs\/2026\/04\/26\/chain-of-command-in-d365-fo-a-practitioners-guide-to-when-and-when-not-to-use-it\/\">Chain of Command in D365 F&amp;O<\/a>\u00a0<\/p>\n\n\n\n<p><strong>The three kinds of &#8220;event handler&#8221; \u2014 they are not the same<\/strong>&nbsp;<\/p>\n\n\n\n<p>First,&nbsp;a clarification&nbsp;that saves hours of confusion later. When F&amp;O developers&nbsp;say&nbsp;&#8220;event handler,&#8221; they mean one of three different things. Microsoft&#8217;s docs treat them as one family, but the decision calculus is different for each.&nbsp;<\/p>\n\n\n\n<p><strong>1. Pre\/Post handlers on methods \u2014&nbsp;<\/strong>the&nbsp;[PreHandlerFor]&nbsp;and&nbsp;[PostHandlerFor]&nbsp;attributes. These wrap a specific method the same way CoC does, and&nbsp;they&#8217;re&nbsp;the direct alternative to CoC for method-level logic overrides.&nbsp;<\/p>\n\n\n\n<p><strong>2. Data\/form event handlers \u2014&nbsp;<\/strong>[DataEventHandler]&nbsp;for table events (OnInserting,&nbsp;OnInserted,&nbsp;OnUpdating, and so on), and&nbsp;[FormEventHandler],&nbsp;[FormDataSourceEventHandler],&nbsp;[FormControlEventHandler]&nbsp;for their form equivalents. These are&nbsp;<em>not<\/em>&nbsp;method overrides. They are framework events \u2014 hooks that fire at specific lifecycle points, and CoC has no equivalent for most of them.&nbsp;<\/p>\n\n\n\n<p><strong>3. Delegate subscribers \u2014&nbsp;<\/strong>[SubscribesTo]. Microsoft (and well-designed ISV code) publishes&nbsp;delegate&nbsp;declarations at designated extension points. You subscribe to them with the&nbsp;SubscribesTo&nbsp;attribute. This is the cleanest, most forward-compatible form of extension \u2014 when a delegate exists for what you need, use it.&nbsp;<\/p>\n\n\n\n<p>Conflating these three is the source of most of the &#8220;I&#8217;ve heard CoC is better&#8221; confusion&nbsp;you&#8217;ll&nbsp;see in community threads. CoC only competes with category 1. For categories 2 and 3, there is no CoC alternative \u2014 handlers are the only game in town.&nbsp;<\/p>\n\n\n\n<p><strong>Pre\/Post handler anatomy \u2014 the version that&nbsp;actually competes&nbsp;with CoC<\/strong>&nbsp;<\/p>\n\n\n\n<p>A Pre or Post handler is a static method&nbsp;on&nbsp;a class, decorated with an attribute that binds it to a specific base method. The handler receives a single&nbsp;XppPrePostArgs&nbsp;parameter that carries&nbsp;this, the&nbsp;method&nbsp;arguments, and (for Post handlers) the return value.&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public static class MyTableEventHandler \n{ \n    &#91;PostHandlerFor(tableStr(SalesTable), tableMethodStr(SalesTable, validateField))] \n    public static void SalesTable_Post_validateField(XppPrePostArgs _args) \n    { \n        SalesTable salesTable = _args.getThis(); \n        FieldId   fieldId    = _args.getArg(\"_fieldId\"); \n        boolean   ret        = _args.getReturnValue(); \n\n        \/\/ additional validation here \n        _args.setReturnValue(ret); \n    } \n} <\/code><\/pre>\n\n\n\n<p>That&#8217;s&nbsp;the pattern. Compared to the CoC version of the same override, note&nbsp;what&#8217;s&nbsp;happening:&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The handler is\u00a0static. No instance. No access to protected members of the base class.\u00a0<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Arguments are retrieved by string name \u2014\u00a0_args.getArg(&#8220;_fieldId&#8221;). If Microsoft later renames the parameter, the string still &#8220;compiles&#8221; but silently returns the wrong value (or null). This is the brittleness Microsoft warns about.\u00a0<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Return value is read and written through the\u00a0args\u00a0object rather than by expression. Fine in Post; meaningless in Pre (you can\u00a0setReturnValue\u00a0in a Pre\u00a0handler\u00a0but it\u00a0won&#8217;t\u00a0influence the base method \u2014 the base method\u00a0hasn&#8217;t\u00a0run yet).\u00a0<\/li>\n<\/ul>\n\n\n\n<p>Microsoft&#8217;s official documentation on this page (learn.microsoft.com\/&#8230;\/xpp-events) contains one of the most useful sentences in the entire F&amp;O dev reference:&nbsp;<em>&#8220;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.&#8221;<\/em>&nbsp;That&#8217;s&nbsp;Microsoft telling you, on their own reference page, that these handlers are inherently more fragile than CoC. Worth reading twice.&nbsp;<\/p>\n\n\n\n<p><strong>Data event handlers \u2014 the non-negotiable use case for handlers<\/strong>&nbsp;<\/p>\n\n\n\n<p>Table events like&nbsp;OnInserting,&nbsp;OnInserted,&nbsp;OnUpdating,&nbsp;OnDeleting,&nbsp;OnDeleted,&nbsp;OnValidatedField&nbsp;don&#8217;t&nbsp;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.&nbsp;You cannot CoC-wrap them.&nbsp;A&nbsp;[DataEventHandler]&nbsp;subscription is the only extension mechanism.&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;DataEventHandler(tableStr(CustTable), DataEventType::Inserting)] \npublic static void CustTable_onInserting(Common _sender, DataEventArgs _e) \n{ \n    CustTable custTable = _sender as CustTable; \n    \/\/ enrich the record before the insert actually runs \n} <\/code><\/pre>\n\n\n\n<p>Same pattern for form controls (OnClicked,&nbsp;OnModified) and form data sources (OnInitialized,&nbsp;OnActivated,&nbsp;OnWritten). None of these have a CoC alternative. If someone tells&nbsp;you&nbsp;&#8220;always use CoC,&#8221;&nbsp;they&#8217;ve&nbsp;never had to react to a form-load event.&nbsp;<\/p>\n\n\n\n<p><strong>Delegate subscribers \u2014 the cleanest extension&nbsp;point&nbsp;when one exists<\/strong>&nbsp;<\/p>\n\n\n\n<p>Microsoft publishes&nbsp;delegate&nbsp;declarations at many designated extension points throughout standard F&amp;O code \u2014 particularly in posting, validation, and pricing flows. These are explicit invitations to extend&nbsp;behaviour&nbsp;cleanly. When a delegate exists for the scenario you need, it is&nbsp;almost always&nbsp;the right answer, ahead of both CoC and Pre\/Post handlers.&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;SubscribesTo( \n    classStr(FMRentalCheckoutProcessor), \n    delegateStr(FMRentalCheckoutProcessor, RentalTransactionAboutToBeFinalizedEvent))] \n\npublic static void RentalFinalizedEventHandler( \n    FMRental rentalRecord, Struct rentalConfirmation) \n{ \n    \/\/ respond to the published event \n} <\/code><\/pre>\n\n\n\n<p>Two properties make delegates the safest choice when available. First, the method signature is enforced at compile time \u2014 a signature change in the base class fails your build instead of silently breaking your handler (unlike Pre\/Post handlers). Second, delegates are Microsoft&#8217;s explicit contract that&nbsp;<em>this is a supported extension point<\/em>. They are less likely to move or be re-implemented in future updates than a&nbsp;randomly-chosen&nbsp;internal method.&nbsp;Docentric&#8217;s&nbsp;writeup on delegates has the best community-level explanation&nbsp;I&#8217;ve&nbsp;found of how return-value-carrying delegates work using&nbsp;EventHandlerResult&nbsp;\u2014 linked below.&nbsp;<\/p>\n\n\n\n<p><strong>The capability comparison \u2014 side by side<\/strong>&nbsp;<\/p>\n\n\n\n<p>The short table from yesterday was a decision helper.&nbsp;Here&#8217;s&nbsp;the fuller capability grid \u2014 each row is something that either tool can or&nbsp;can&#8217;t&nbsp;do:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><div class=\"pcrstb-wrap\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Capability<\/strong>&nbsp;<\/td><td><strong>Chain of Command<\/strong>&nbsp;<\/td><td><strong>Event Handler<\/strong>&nbsp;<\/td><\/tr><tr><td>Access to protected members of the base class&nbsp;<\/td><td><strong>Yes<\/strong>&nbsp;<\/td><td>No \u2014 the classic limitation&nbsp;<\/td><\/tr><tr><td>Runs in the same transaction scope as the method&nbsp;<\/td><td><strong>Yes<\/strong>&nbsp;<\/td><td>Different context \u2014 use carefully in&nbsp;ttsbegin&nbsp;blocks&nbsp;<\/td><\/tr><tr><td>Can change return value&nbsp;<\/td><td><strong>Directly<\/strong>&nbsp;<\/td><td>Yes, via&nbsp;args.setReturnValue() in Post handler&nbsp;<\/td><\/tr><tr><td>Can change method parameters&nbsp;<\/td><td><strong>Directly on the arguments to next<\/strong>&nbsp;<\/td><td>Indirectly, via&nbsp;args.getArg\/setArg&nbsp;<\/td><\/tr><tr><td>Works on framework\/data events (OnInserting,&nbsp;OnModified, etc.)&nbsp;<\/td><td>No&nbsp;<\/td><td><strong>Yes \u2014 this is what event handlers are for<\/strong>&nbsp;<\/td><\/tr><tr><td>Works on Microsoft-published delegates&nbsp;<\/td><td>No&nbsp;<\/td><td><strong>Yes, via [SubscribesTo]<\/strong>&nbsp;<\/td><\/tr><tr><td>Call order is guaranteed&nbsp;<\/td><td><strong>No \u2014 random<\/strong>&nbsp;<\/td><td>No \u2014 attribute-bound, no sequence guarantee&nbsp;<\/td><\/tr><tr><td>Forced to invoke the base&nbsp;behaviour&nbsp;<\/td><td><strong>Yes (must call next, except on [Replaceable])<\/strong>&nbsp;<\/td><td>No \u2014 pre\/post are strictly around the base, never instead of it&nbsp;<\/td><\/tr><tr><td>Brittle to base-method signature changes&nbsp;<\/td><td><strong>Compile-time error if signature drifts<\/strong>&nbsp;<\/td><td>Silent break: handler stops firing or&nbsp;args&nbsp;resolve wrong&nbsp;<\/td><\/tr><\/tbody><\/table><\/div><\/figure>\n\n\n\n<p><strong>Four real scenarios \u2014 and the correct choice for each<\/strong>&nbsp;<\/p>\n\n\n\n<p><strong>Scenario 1: &#8220;When a sales order is saved, push a message to an integration queue.&#8221;<\/strong>&nbsp;<\/p>\n\n\n\n<p><strong>Right tool: Data event handler on&nbsp;<\/strong><strong>SalesTable<\/strong><strong>&nbsp;with&nbsp;<\/strong><strong>DataEventType::Inserted<\/strong><strong>.<\/strong>&nbsp;<\/p>\n\n\n\n<p>You&#8217;re&nbsp;reacting to an event, not overriding logic. You&nbsp;don&#8217;t&nbsp;need to change the insert&nbsp;behaviour, read protected fields, or influence a return value. A&nbsp;DataEventHandler&nbsp;is clearer and more maintainable than CoC on&nbsp;insert() or&nbsp;update() \u2014 and as of Platform Update 22, even the&nbsp;insert() CoC option is newer than the&nbsp;DataEventHandler&nbsp;pattern, which has been stable for years. \u26a0 Be mindful that&nbsp;OnInserted&nbsp;fires after the insert commits; if you need pre-commit logic, use&nbsp;OnInserting.&nbsp;<\/p>\n\n\n\n<p><strong>Scenario 2: &#8220;Validate a custom field on vendor master; reject the save if invalid.&#8221;<\/strong>&nbsp;<\/p>\n\n\n\n<p><strong>Right tool: Chain of Command on&nbsp;<\/strong><strong>VendTable.validateWrite()<\/strong><strong>.<\/strong>&nbsp;<\/p>\n\n\n\n<p>You need to change the return value&nbsp;conditionally&nbsp;and you need access to the full record state including protected members. A Post handler on&nbsp;validateWrite&nbsp;would technically work via&nbsp;_args.setReturnValue(false), but CoC reads dramatically cleaner and is&nbsp;signature-stable.&nbsp;<\/p>\n\n\n\n<p><strong>Scenario 3: &#8220;Show a warning to the user when a purchase order with a specific item is opened.&#8221;<\/strong>&nbsp;<\/p>\n\n\n\n<p><strong>Right tool: Form data source event handler on&nbsp;<\/strong><strong>OnInitialized<\/strong><strong>&nbsp;(or a form control event handler depending on exact trigger).<\/strong>&nbsp;<\/p>\n\n\n\n<p>This is a framework event. There is no corresponding X++ method to wrap. CoC&nbsp;doesn&#8217;t&nbsp;apply. If you find yourself trying to&nbsp;CoC&nbsp;a form method here, step back \u2014 the form-nested CoC support in F&amp;O covers data source and control methods but not every framework event.&nbsp;<\/p>\n\n\n\n<p><strong>Scenario 4: &#8220;Add custom posting logic during sales invoice posting.&#8221;<\/strong>&nbsp;<\/p>\n\n\n\n<p><strong>Right tool: check for a Microsoft-published delegate first. If found, use&nbsp;<\/strong><strong>[SubscribesTo]<\/strong><strong>. If none exists, CoC on the specific posting method.<\/strong>&nbsp;<\/p>\n\n\n\n<p>Posting flows are one area where Microsoft has published many delegates specifically to avoid&nbsp;people&nbsp;monkey-patching core posting logic. Spend ten minutes looking for one before you&nbsp;CoC&nbsp;a posting method \u2014 the delegate path is dramatically safer for upgrades.&nbsp;<\/p>\n\n\n\n<p><strong>The decision flowchart, in prose<\/strong>&nbsp;<\/p>\n\n\n\n<p>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 &#8220;yes&#8221;.&nbsp;<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li>Is there a Microsoft-published delegate for this scenario? \u2192 Use [SubscribesTo].\u00a0<\/li>\n<\/ol>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li>Is the thing I want to react to a framework\/data event (OnInserting,\u00a0OnClicked, etc.), not a\u00a0method\u00a0body? \u2192 Use the\u00a0appropriate event\u00a0handler ([DataEventHandler], [FormControlEventHandler], etc.).\u00a0<\/li>\n<\/ol>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li>Do I need to override the logic of a specific public or protected method? \u2192 Default to CoC.\u00a0<\/li>\n<\/ol>\n\n\n\n<ol start=\"4\" class=\"wp-block-list\">\n<li>Is that method marked [Hookable(false)] or [Wrappable(false)] without a\u00a0Wrappable(true) escape? \u2192 Fall back to a Pre or Post handler if the method is still\u00a0subscribable, or redesign.\u00a0<\/li>\n<\/ol>\n\n\n\n<ol start=\"5\" class=\"wp-block-list\">\n<li>Do I need access to protected fields or methods of the base class? \u2192 CoC is the only\u00a0option\u00a0that gives you this cleanly.\u00a0<\/li>\n<\/ol>\n\n\n\n<ol start=\"6\" class=\"wp-block-list\">\n<li>Am I doing simple before-or-after logic that\u00a0doesn&#8217;t\u00a0need protected access, parameter modification, or transaction-scope-matching? \u2192 Either works; prefer Pre\/Post only if you have a reason not to prefer CoC.\u00a0<\/li>\n<\/ol>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img decoding=\"async\" width=\"672\" height=\"328\" src=\"https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/post-2-img-3.png\" alt=\"\" class=\"wp-image-1415\" style=\"width:701px;height:auto\" srcset=\"https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/post-2-img-3.png 672w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/post-2-img-3-300x146.png 300w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/post-2-img-3-585x286.png 585w\" sizes=\"(max-width: 672px) 100vw, 672px\" \/><\/figure>\n\n\n\n<p><strong>3 tricky interview questions (with verified answers)<\/strong>&nbsp;<\/p>\n\n\n\n<p>As with yesterday&#8217;s post, each answer is grounded in named, verifiable sources (linked in the References section).&nbsp;<\/p>\n\n\n\n<p><strong>Q1. A Pre handler and a CoC extension both wrap the same method. Which one runs first?<\/strong>&nbsp;<\/p>\n\n\n\n<p>Trick answer. Microsoft&#8217;s documentation is explicit that neither subscribers nor CoC extensions have a guaranteed sequence. The CoC docs say the system&nbsp;<em>&#8220;randomly picks&#8221;<\/em>&nbsp;among wrapped methods, and the events reference page states:&nbsp;<em>&#8220;Since the binding between the publisher and subscribers is done through attributes, there&#8217;s no way of specifying the sequence in which subscribers are called.&#8221;<\/em>&nbsp;Sertan Yaman&#8217;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&nbsp;order-independence&nbsp;\u2014 assuming &#8220;pre handler runs first&#8221; is a bug waiting to happen.&nbsp;<\/p>\n\n\n\n<p><strong>Q2. How do you pass&nbsp;state&nbsp;between a Pre handler and a Post handler on the same method?<\/strong>&nbsp;<\/p>\n\n\n\n<p>Both handlers are&nbsp;static&nbsp;methods&nbsp;on&nbsp;a handler class. Na\u00efve&nbsp;option: a static field&nbsp;on&nbsp;that class \u2014 works for single-threaded cases but is fragile under concurrent calls. The cleaner, documented community technique (Ievgen&#8217;s&nbsp;AX blog, hosted on community.dynamics.com) uses&nbsp;XppPrePostArgs&nbsp;itself as the carrier:&nbsp;_args.addArg(&#8216;myFlag&#8217;, value)&nbsp;in the Pre handler,&nbsp;_args.getArg(&#8216;myFlag&#8217;)&nbsp;in the Post handler. The&nbsp;args&nbsp;collection is per-invocation, so state travels with the call rather than sitting in a shared field. \u26a0 This relies on undocumented-but-stable&nbsp;behaviour&nbsp;of&nbsp;XppPrePostArgs; if this is critical path code, wrap it in a comment explaining what&nbsp;you&#8217;re&nbsp;doing and why.&nbsp;<\/p>\n\n\n\n<p><strong>Q3. Can you&nbsp;subscribe&nbsp;a Pre\/Post event handler to a protected or private method on a standard class?<\/strong>&nbsp;<\/p>\n\n\n\n<p>Directly, no. By default, only public methods are&nbsp;subscribable. Sertan Yaman documents a legacy workaround: overlayer the standard object and add a&nbsp;[Hookable(true)]&nbsp;attribute on the protected method. This is a relic of the&nbsp;overlayering&nbsp;era and is not recommended for modern F&amp;O \u2014&nbsp;overlayering&nbsp;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 \u2014 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 &#8220;just overlayer and add&nbsp;Hookable(true),&#8221;&nbsp;that&#8217;s&nbsp;a signal they learned F&amp;O in the AX 2012 era and&nbsp;haven&#8217;t&nbsp;updated their mental model.&nbsp;<\/p>\n\n\n\n<p><strong>What to&nbsp;actually do<\/strong>&nbsp;<\/p>\n\n\n\n<ol start=\"7\" class=\"wp-block-list\">\n<li>Don&#8217;t\u00a0treat &#8220;CoC vs event handlers&#8221; as one question.\u00a0It&#8217;s\u00a0three: (a) method override \u2014 CoC vs Pre\/Post, (b) framework event \u2014 use the\u00a0appropriate data\/form\u00a0event handler, (c) published extension point \u2014 use\u00a0SubscribesTo. The wrong grouping is most of the confusion.\u00a0<\/li>\n<\/ol>\n\n\n\n<ol start=\"8\" class=\"wp-block-list\">\n<li>Default order of preference for reaction:\u00a0SubscribesTo\u00a0(if a delegate exists) \u2192 data\/framework event handler (if the trigger is an event) \u2192 CoC (if\u00a0you&#8217;re\u00a0overriding method logic) \u2192 Pre\/Post (only when CoC is blocked or unavailable).\u00a0<\/li>\n<\/ol>\n\n\n\n<ol start=\"9\" class=\"wp-block-list\">\n<li>Never rely on call order \u2014 between handlers, between CoC extensions, or between the two. Microsoft&#8217;s docs say\u00a0it&#8217;s\u00a0random; community tests confirm it; your bug reports will too if you ignore this.\u00a0<\/li>\n<\/ol>\n\n\n\n<ol start=\"10\" class=\"wp-block-list\">\n<li>Take Microsoft&#8217;s own warning seriously: Pre\/Post handlers are more fragile than CoC. Prefer CoC for method overrides when both are\u00a0feasible.\u00a0<\/li>\n<\/ol>\n\n\n\n<p><strong>References<\/strong>&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Microsoft Learn<\/strong>\u00a0\u2014 Events and delegates (learn.microsoft.com\/en-us\/dynamics365\/fin-ops-core\/dev-itpro\/dev-ref\/xpp-events). Authoritative. Covers delegate syntax,\u00a0SubscribesTo\u00a0attribute, Pre\/Post handler pattern, and the explicit fragility warning. Last updated February 2025.\u00a0<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Microsoft Learn<\/strong>\u00a0\u2014 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\u00a0Wrappable\/Hookable\u00a0attribute semantics.\u00a0<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Sertan Yaman<\/strong>\u00a0\u2014 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\u00a0PreHandlerFor\u00a0\/\u00a0PostHandlerFor\u00a0example code on\u00a0InventTable, and the overlayer + [Hookable(true)] workaround for protected methods referenced in Q3.\u00a0<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Docentric<\/strong>\u00a0\u2014 Delegates and Event Handlers in D365FO (ax.docentric.com\/delegates-and-event-handlers-in-d365fo\/). Best community-level explanation of delegates, return-carrying\u00a0EventHandlerResult\u00a0pattern, and when to prefer\u00a0SubscribesTo\u00a0over other extension mechanisms. Updated\u00a0February\u00a02026.\u00a0<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Ievgen&#8217;s\u00a0AX blog<\/strong>\u00a0\u2014 Trick to pass a value between Pre and Post event\u00a0handler\u00a0using\u00a0XppPrePostArgs\u00a0(community.dynamics.com). Source for the Q2 answer on carrying state between handlers via the\u00a0args\u00a0object.\u00a0<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Mastering D365FO<\/strong>\u00a0\u2014 Event Handlers in D365FO with Practical Examples (masteringd365fo.blogspot.com, April 2025). Practical Table, Form, and\u00a0DataSource\u00a0event handler patterns with current code samples.\u00a0<\/li>\n<\/ul>\n\n\n\n<p><em>Next up in this series: The 5 X++ Extension Pitfalls I See on Almost Every Project. Shorter post, opinion&nbsp;voice, list format.<\/em>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Reading time: ~9 minutes.\u00a0 Yesterday&#8217;s post argued that Chain of Command is usually the right tool for overriding F&amp;O method logic. That was deliberately one-sided \u2014 you&nbsp;can&#8217;t&nbsp;teach a decision framework&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_lmt_disableupdate":"","_lmt_disable":"","footnotes":""},"categories":[1],"tags":[],"class_list":["post-1409","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/posts\/1409","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/comments?post=1409"}],"version-history":[{"count":6,"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/posts\/1409\/revisions"}],"predecessor-version":[{"id":1418,"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/posts\/1409\/revisions\/1418"}],"wp:attachment":[{"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/media?parent=1409"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/categories?post=1409"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/tags?post=1409"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}