AL Development

AL Event Subscribers Explained: Extending Business Central Safely

By Central Era TechnologiesPublished 19 September 20264 min read

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:

  1. Look for an event specific to the action, such as a "before posting" or "after creating" event on the relevant codeunit.
  2. If none exists, use a database trigger event on the table, and check Rec.IsTemporary() and RunTrigger where relevant.
  3. 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.

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.

Central Era TechnologiesWritten by the consultants and developers at Central Era Technologies, who work with Business Central, Dynamics 365 Finance and Operations, Power Platform and Azure. To credit a named author, add one here.

Working on something similar?

If this article touches a project you are planning or a problem you are stuck on, tell us about it. We will reply with practical next steps.