Events are how AL extensions change what Business Central does without modifying its code. Microsoft's code raises an event at a defined point; your extension subscribes and runs its own logic. This article explains the model, shows working examples, and lists the pitfalls that cause the most trouble.
Publishers and subscribers
An event publisher is a procedure that announces "something is happening here". It has no body. An event subscriber is a procedure in another object that Business Central calls whenever the publisher is raised. Because the connection is declared through an attribute, the publisher does not know who is listening, which is what keeps extensions and the base application independent.
There are several kinds of publishers:
- Integration events: raised by code at meaningful points, such as before or after posting a document.
- Business events: a stable contract for external consumers, whose signature Microsoft commits to keep.
- Database trigger events: raised on table operations (
OnBeforeInsertEvent,OnAfterModifyEvent,OnAfterDeleteEvent) and on field validation (OnBeforeValidateEvent,OnAfterValidateEvent).
Example 1: validate a field
To reject a negative credit limit on customers, subscribe to the validate event for that field:
codeunit 50121 "CE Customer Events"
{
[EventSubscriber(ObjectType::Table, Database::Customer, 'OnAfterValidateEvent', 'Credit Limit (LCY)', false, false)]
local procedure ValidateCreditLimit(var Rec: Record Customer; var xRec: Record Customer; CurrFieldNo: Integer)
begin
if Rec."Credit Limit (LCY)" < 0 then
Error('The credit limit cannot be negative.');
end;
}
The attribute says: for the table Customer, on the event OnAfterValidateEvent, for the field Credit Limit (LCY). The last two arguments (SkipOnMissingLicense and SkipOnMissingPermission) should normally stay false, so that problems are visible instead of silently skipped.
Example 2: publish your own events
When you write your own logic, give other extensions, and your future self, a way to influence it. The common pattern is a "before" event with an IsHandled flag and an "after" event to adjust results:
codeunit 50120 "CE Shipping Fee Mgt"
{
procedure CalculateFee(var SalesHeader: Record "Sales Header"): Decimal
var
Fee: Decimal;
IsHandled: Boolean;
begin
OnBeforeCalculateFee(SalesHeader, Fee, IsHandled);
if IsHandled then
exit(Fee);
Fee := 100; // default rule
OnAfterCalculateFee(SalesHeader, Fee);
exit(Fee);
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCalculateFee(var SalesHeader: Record "Sales Header"; var Fee: Decimal; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterCalculateFee(var SalesHeader: Record "Sales Header"; var Fee: Decimal)
begin
end;
}
A subscriber that sets IsHandled := true and provides its own Fee replaces the default calculation, and one that only adjusts Fee in the "after" event refines it. You will see the same IsHandled pattern throughout Microsoft's own code.
Finding the right event
In practice, the hard part is choosing the event. Approach it in order:
- Look for an event specific to the action, such as a "before posting" or "after creating" event on the relevant codeunit.
- If none exists, use a database trigger event on the table, and check
Rec.IsTemporary()andRunTriggerwhere relevant. - If neither fits, use Microsoft's process for requesting a new event, or, for your own code, add one.
Use the AL debugger, or search the base application source with the AL Language extension's symbol navigation, to see where events fire and with what parameters.
Pitfalls
- Assuming order. If several subscribers listen to one event, do not depend on which runs first.
- Heavy subscribers on hot paths. Events fire inside posting and validation. A slow subscriber slows every document, so keep them small and filter early.
- Ignoring
IsHandled. If you replace behaviour, set it; if you don't, check it before doing your work. - Hidden side effects. Subscribers change behaviour from a distance. Name codeunits by purpose and document what each subscriber does.
- Breaking changes. Integration event signatures can change between versions. Test your extension against upcoming releases in a sandbox.
- No tests. Because the effect is indirect, an automated test around the process is the only reliable safety net.
Related reading
New to AL? Start with What is AL in Business Central?. For outbound integration, see HttpClient and JSON in AL. To have this designed and built for you, visit our customization and AL development pages, and to learn it, look at the technical training.
Key takeaways
- Events are the main extension mechanism: publishers announce, subscribers react.
- Subscribe to the most specific event available and keep subscribers small.
- Respect IsHandled parameters and never assume the order subscribers run in.
- Test subscribers, because they change behaviour from a distance.
