Extensibility Edge Cases in Dynamics 365 Finance & Operations
Question 58 — What to do when a method, class or element is not extensible.
Interview Question
private/final, a class is sealed, or an element
(like a report) cannot be extended? How do you handle these edge cases the
upgrade-safe way?
Model Answer (Short)
Since over-layering is deprecated, you must always reach for an extension first — but some targets aren't hookable. The strategy depends on what's blocking you. If a method isn't wrappable, look for a nearby delegate or Pre/Post event, or wrap a caller higher up that is extensible. If a class/method is sealed/private/final and Microsoft hasn't opened it, the correct route is to raise an extensibility request to Microsoft (they add hooks/attributes) — not to fork or copy the code. For report objects (which aren't extensible) you duplicate the report but extend the controller/DP/temp classes. As a last resort you can duplicate a small, isolated piece of standard logic — but this is discouraged because it won't receive Microsoft updates. The golden rule: extension → event/delegate → wrap a caller → request extensibility → (rarely) duplicate.
The Decision Ladder
Try these in order
- 1. Chain of Command — wrap the method if it's public/protected and not final.
- 2. Delegate / Pre-Post event — if the method itself isn't wrappable, subscribe to an available delegate or event.
- 3. Wrap a caller — extend a higher-level method that is hookable and calls the blocked one.
- 4. Request extensibility from Microsoft — ask them to add a hookable seam (attribute/delegate).
- 5. Duplicate (last resort) — copy a small isolated piece; accept it won't get updates.
Why not over-layer or fork?
- Over-layering is deprecated for customer/partner code.
- Forking/duplicating means you miss Microsoft updates and hotfixes.
- It increases upgrade and maintenance cost and risk.
- Only duplicate a small, well-isolated piece when there's truly no seam.
Common Non-Extensible Situations
| Blocker | Recommended approach |
|---|---|
Method is final | Find a delegate/event or wrap a non-final caller |
Method/class is private | Wrap a public caller, or request extensibility |
| Class is sealed | Request Microsoft to open it; use surrounding events |
| Report object | Duplicate the report; extend controller/DP/temp classes |
| No hook anywhere | Raise an extensibility request; duplicate only as last resort |
Prerequisites (Rule 5)
- Visual Studio with the Dynamics 365 developer tools.
- A custom model / package for your objects.
- Access to cross-reference to find callers and available delegates/events.
- A channel to submit Microsoft extensibility requests (via support/LCS).
Code Example — Wrap a hookable caller instead of the blocked method
// The low-level method is final/private and cannot be wrapped.
// Instead, wrap the PUBLIC caller that invokes it.
[ExtensionOf(classStr(AbcPostingEngine))]
final class AbcPostingEngineAbc_Extension
{
public void postDocument(AbcDocument _doc)
{
// Pre-logic before the (non-hookable) internal posting runs
this.abcValidateBeforePost(_doc);
next postDocument(_doc); // caller IS hookable
// Post-logic after posting
this.abcNotifyAfterPost(_doc);
}
}
Subscribe to an available delegate when the method isn't wrappable
class AbcPostingSubscriber
{
[SubscribesTo(classStr(AbcPostingEngine),
delegateStr(AbcPostingEngine, postingCompletedDelegate))]
public static void onPostingCompleted(AbcDocumentId _docId)
{
// React to the event Microsoft exposed, instead of editing the method
info(strFmt("Posting completed for %1", _docId));
}
}
Report edge case — duplicate report, extend the classes
// Report OBJECT is duplicated (not extensible), but the controller
// is EXTENDED so standard behaviour is reused.
class AbcSalesReportController extends SrsReportRunController
{
public static void main(Args _args)
{
AbcSalesReportController controller = new AbcSalesReportController();
controller.parmReportName(ssrsReportStr(AbcSalesReport, Report)); // duplicated report
controller.parmArgs(_args);
controller.startOperation();
}
}
Points the interviewer wants to hear
- Always prefer CoC → event/delegate → wrap a caller before anything drastic.
- If nothing is hookable, request extensibility from Microsoft.
- Report objects aren't extensible — duplicate the report, extend the classes.
- Duplicating standard logic is a last resort (no updates).
- Never over-layer or fork — it's deprecated and unsupported.
Likely Follow-up Questions
- What do you do when the method you need to change is
final? - How do you customize a standard report if it isn't extensible?
- What is a Microsoft extensibility request and when do you raise one?
- Why is duplicating standard code discouraged?
Key Takeaway
When a target isn't extensible, climb the ladder: Chain of Command → event/delegate → wrap a hookable caller → request extensibility from Microsoft → (rarely) duplicate. For reports, duplicate the object but extend the classes. Never over-layer or fork — it breaks the upgrade-safe promise.