Write an event handler
Updated
Every dictionary and document has a module Events/<Name>EventHandler.*. Empty
templates are normal — fill them, do not recreate them. Class names are unique
across the whole workspace: the first handler is <Name>EventHandler; the next
link in the chain uses a suffix (<Name>ExtEventHandler, <Name>Tx_<Model>).
Note
The owner — the handler in the object's own model — is link 0 and does not call
next. A handler on somebody else's object must declare[ExtensionOf("ObjectName")]and callnextfrom every override. See Chain of Command.
How to#
public partial class CustomerEventHandler : TypedDictionaryEventHandler<Customer>
{
public override Task<EventResult> OnBeforeSaveAsync(
Customer record, bool isNew, EventContext context)
{
if (string.IsNullOrEmpty(record.Name))
return Task.FromResult(EventResult.Cancel(Res.NameRequired));
return Task.FromResult(EventResult.Ok());
}
}
The pair is the envelope (*.script.json) plus the user partial (*.cs).
Commit both. Override only the hooks you need; an extra override is a dead
line, not a template.
| Hook | When |
|---|---|
OnValidateField / OnFieldChanged |
A field on the card, no Save. Fill only empty dependents — Save runs the same hooks |
OnBeforeSave / OnAfterSave |
Persist |
OnBeforePost / OnAfterPost |
A document subtype transition (and unpost) |
On a table part, the header is Owner<Document>(context).
Text the user will read is a resource on this
script (Res.NameRequired), not a C# literal. Identifiers (subtype values,
analytic names, cache keys) stay strings in code.
Do not read a second table in a create event. Put that lookup on a
command. OnAfterPostAsync can run twice (repost, and a totals driver that
posts under the same doc id). Anything outside the document — a spawned
child, a tax submission, an outbound call — must be idempotent. Movements of
the document itself are replaced, not added.
Tip
A script cannot open files, sockets, processes, or reflect around the platform. Outbound I/O goes through
IOutboundGateway/IOutboundCallby channel name. See what a script can do and outbound integrations.
Platform services are available in every script: IDocumentManager,
IDictionaryManager, IDataEntityManager, IDataService,
IRegisterMovementService, IInformationRegisterService,
IDocumentPostingService, IMetadataService, IConstantResolver, plus your
own I<Name>.
What's not there yet#
Event handlers do not write register movements. That is a posting script.