Chain of Command ou event handlers en X++ : lequel choisir ?
Pour étendre une méthode standard D365 F&O, préférez Chain of Command ; gardez les event handlers pour les événements de table et délégués existants.
La réponse courte
Pour modifier le comportement d'une méthode publique ou protégée d'une classe, d'une table, d'une data entity ou d'un formulaire, utilisez Chain of Command (CoC) : une classe d'extension qui « enveloppe » la méthode et appelle next. C'est le mécanisme que Microsoft présente comme plus riche et plus robuste ; sa documentation sur les délégués recommande même de ne plus en créer de nouveaux et de passer par CoC.
Les event handlers restent utiles dans trois cas : réagir aux événements de données d'une table (Inserting, ValidatedWrite, etc.), s'abonner à un délégué déjà publié par Microsoft, et les pré/post-handlers hérités sur du code qui ne peut pas être enveloppé. Microsoft précise que les pré/post-handlers existent surtout pour la compatibilité et cassent facilement quand la signature de la méthode change.
Comment fonctionne Chain of Command ?
On crée une classe finale décorée avec ExtensionOf, puis on redéclare la méthode avec la même signature. L'appel à next exécute la méthode suivante de la chaîne puis, à la fin, l'implémentation d'origine. Exemple tiré de Microsoft Learn :
[ExtensionOf(classStr(BusinessLogic1))]
final class BusinessLogic1_Extension
{
str doSomething(int arg)
{
// Avant
var s = next doSomething(arg + 4);
// Après
return s;
}
}Ce qu'apporte CoC : accès aux méthodes et variables publiques et protégées de la classe étendue, possibilité d'agir avant et après l'appel standard, de modifier les paramètres ou la valeur de retour, et de gérer une transaction dans la même méthode. Cela fonctionne pour les méthodes d'instance et statiques (avec le mot-clé static), pour les tables, les data entities, les formulaires et, via une extension par concept, pour les data sources, data fields et contrôles de formulaire.
Pour une table, le même principe s'applique :
[ExtensionOf(tableStr(TableToExtend))]
final class TableToExtend_Extension
{
public boolean validateWrite()
{
boolean ret;
ret = next validateWrite();
// Contrôle supplémentaire
return ret;
}
}Quelles règles respecter avec next ?
La méthode d'enveloppe doit toujours appeler next, au premier niveau du corps de la méthode :
- pas d'appel à next dans un if, ni dans une boucle while, do-while ou for ;
- pas de return avant next ;
- pas de next dans une expression logique ;
- next peut être placé dans un try/catch/finally depuis la Platform update 21.
Exception : si la méthode standard porte l'attribut Replaceable, le compilateur n'impose pas l'appel à next ; Microsoft attend alors que la chaîne ne soit interrompue que de façon conditionnelle.
Autres limites documentées : une méthode marquée final ou [Wrappable(false)] ne peut pas être enveloppée (sauf [Wrappable(true)] sur une méthode final) ; [Hookable(false)] bloque à la fois CoC et les pré/post-handlers ; les constructeurs ne peuvent pas être étendus ; la valeur par défaut d'un paramètre ne doit pas être répétée dans la signature de l'enveloppe ; l'ordre d'exécution entre plusieurs extensions d'une même méthode n'est pas garanti.
Quand garder un event handler ?
Les tables publient des événements de données avant et après leurs méthodes : ValidatingWrite / ValidatedWrite, Inserting / Inserted, Updating / Updated, Deleting / Deleted, ModifyingField / ModifiedField, InitializingRecord / InitializedRecord, etc. S'y abonner (DataEventHandler) est simple et lisible pour remplir un champ ou ajouter un contrôle. Les événements de validation passent leur résultat par DataEventArgs.
Les délégués publiés par Microsoft s'écoutent avec l'attribut SubscribesTo ; l'ordre d'appel entre abonnés ne peut pas être fixé.
Enfin, les pré/post-handlers (PreHandlerFor / PostHandlerFor) existent toujours :
[PostHandlerFor(classStr(MyClass2), methodStr(MyClass2, publisher))]
public static void PostHandler(XppPrePostArgs arguments)
{
int arg = arguments.getArg("i");
int retvalFromMethod = arguments.getReturnValue();
}Ils lisent les arguments par leur nom et la valeur de retour via XppPrePostArgs : renommer un paramètre côté Microsoft suffit à les casser. Sur une méthode enveloppable, préférez CoC.
Erreurs fréquentes
- Appeler next dans un if pour « court-circuiter » le standard : refusé par le compilateur, et contraire au modèle d'extension.
- Oublier final sur la classe d'extension ou ExtensionOf avec le mauvais type (classStr, tableStr, formStr, formDataSourceStr…).
- Recopier la valeur par défaut d'un paramètre dans la signature de l'enveloppe.
- Envelopper une méthode X++ « pure » définie dans un data source ou un contrôle de formulaire : Learn indique que le code compile mais que l'extension n'est pas appelée à l'exécution.
- Créer un nouveau délégué dans son propre code au lieu de petites méthodes bien nommées, que d'autres pourront envelopper.
- Supposer un ordre d'exécution entre plusieurs extensions.
Et avec un code généré par IA ?
Le choix CoC / event handler est une décision de conception que toute revue de code doit vérifier, qu'un humain ou une IA ait écrit l'extension. Chez Skalp AI, le code X++ est généré par extension (jamais par over-layering), accompagné de tests unitaires, livré sur votre Azure DevOps et validé par votre DSI avant merge. Voir extensions D365 F&O sur mesure et, si votre code contient encore de l'over-layering, migrer l'over-layering vers les extensions. Pour le cadre général : développer en X++ sans consultant en 2026. Tarifs : offres Basic, Pro et Max, 1 crédit (≈ 400 € en Basic, 200 € en Pro) consommé seulement à la génération du code.
Sources
- Microsoft Learn, « Class extension - Method wrapping and Chain of Command », mise à jour du 27/03/2026, consultée le 11/10/2026.
- Microsoft Learn, « Events and delegates », mise à jour du 31/03/2026, consultée le 11/10/2026.
- Microsoft Learn, « Customize through extension and overlayering » (événements de table), mise à jour du 27/03/2026, consultée le 11/10/2026.
- Microsoft Learn, « Delegates » et « Attributes that make methods extensible », consultées le 11/10/2026.
Questions fréquentes
Peut-on ne pas appeler next dans une méthode Chain of Command ?
Non, sauf si la méthode standard porte l'attribut Replaceable. Dans les autres cas, next doit être appelé au premier niveau de la méthode, hors if, boucle et expression logique.
Faut-il encore créer des délégués ?
Microsoft recommande de ne plus en créer : on peut s'abonner aux délégués existants, mais pour son propre code mieux vaut de petites méthodes bien nommées, extensibles par Chain of Command.
Pourquoi ma méthode ne peut-elle pas être enveloppée ?
Elle est sans doute privée, marquée final sans [Wrappable(true)], marquée [Wrappable(false)] ou [Hookable(false)], ou c'est un constructeur. Vérifiez aussi qu'il ne s'agit pas d'une méthode X++ pure d'un data source ou d'un contrôle de formulaire.
Prêt à transformer votre D365 ?
Rejoignez les DSI qui développent leurs tickets D365 en 1h pour 1 crédit (≈ 400 € en Basic, 200 € en Pro).