Single Instance EventSubscriber in AL

In this video, I show how to combine SingleInstance codeunits with event subscribers to compensate for missing parameters on events.

https://youtu.be/_MiBa2Fms1g

In this tips-and-tricks style video, Erik demonstrates a practical AL pattern: using Single Instance event subscribers to carry data between multiple events in Business Central. When one event gives you a date and another gives you a time — but you need both together — the Single Instance property on a codeunit lets you persist values across event calls.

The Problem: Split Data Across Multiple Events

Imagine you need to work with both a Date and a Time value, but the publisher codeunit fires them in separate events. Here’s the “Trouble Codeunit” that represents this scenario:

codeunit 50112 "Trouble Codeunit"
{
    procedure GreatestCodeOfAllTime()
    begin
        ///
        OnInit();
        ///
        ///
        OnTheFirstEvent('123', 123, calcdate('-34D', Today()));
        ///
        ////
        /// 
        /// 
        ///
        OnTheSecondEvent(Time());
        ////
        /// 
    end;

    [IntegrationEvent(false, false)]
    local procedure OnTheFirstEvent(NumberTxt: Text; Number: Integer; Date: Date)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnTheSecondEvent(Time: Time)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnInit()
    begin
    end;
}

The first event (OnTheFirstEvent) provides a Date, a Number, and a NumberTxt. The second event (OnTheSecondEvent) provides only a Time. If you need to create a DateTime from both values, you’re stuck — neither event gives you everything you need on its own.

The Solution: Single Instance Event Subscribers

The key insight is that when you mark a codeunit with SingleInstance = true, only one instance of that codeunit exists for the duration of the session. This means any global variables you set in one event subscriber will still hold their values when the next event subscriber fires. You can effectively “carry” data from one event to another.

codeunit 50144 "subs"
{
    SingleInstance = true;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Trouble Codeunit", 'OnTheSecondEvent', '', true, true)]
    local procedure OnTheSecondEventSubscriber(Time: Time)
    begin
        message('%1', CreateDateTime(SavedDate, Time));
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Trouble Codeunit", 'OnTheFirstEvent', '', true, true)]
    local procedure OnTheFirstEvent(Date: Date; Number: Integer; NumberTxt: Text)
    begin
        SavedDate := Date;
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Trouble Codeunit", 'OnInit', '', true, true)]
    local procedure OnInit()
    begin
        SavedDate := 0D;
    end;

    var
        SavedDate: Date;
}

How It Works, Step by Step

  1. SingleInstance = true — This property on the subscriber codeunit ensures there is only ever one instance. The SavedDate variable persists across all event calls within the same session.
  2. OnInit subscriber — Resets SavedDate to 0D (zero date) at the start of the process. This ensures you don’t accidentally carry stale data from a previous execution.
  3. OnTheFirstEvent subscriber — Captures the Date parameter and stores it in the SavedDate variable.
  4. OnTheSecondEvent subscriber — Combines the previously saved SavedDate with the Time parameter to create a DateTime, then displays it via Message.

Important Considerations

Execution Order Matters

This pattern only works if you know for certain that the first event fires before the second event — every time, without exception. If there’s a conditional branch in the publisher code that might skip the first event, your saved variable could be empty or stale when the second event fires.

Use an Initialization Event

Since the codeunit is a single instance, variable values survive across multiple calls. That’s why it’s important to subscribe to an initialization event (like OnInit in this example) to reset your stored values. Without this, data from a previous run could leak into the next one.

Naming Conventions

Erik recommends naming your subscriber procedures after the event they subscribe to. This makes it much easier to understand what each subscriber is doing when you revisit the code later.

Why This Happens in Practice

When developers create integration events, it’s genuinely difficult to predict every piece of data a subscriber might need. Providing 25 parameters on every event isn’t practical — it makes the event signature unwieldy and confusing. So sometimes you end up with events that don’t quite give you everything you need. The Single Instance pattern is a clean workaround for these situations.

Summary

The Single Instance event subscriber pattern is a straightforward but powerful trick for Business Central AL development. By setting SingleInstance = true on your subscriber codeunit, you can persist data in global variables across multiple event invocations, effectively bridging the gap when the information you need is spread across separate events. Just make sure the execution order is guaranteed and that you reset your stored values at the appropriate time. No event portfolio is perfect, but patterns like this help you work effectively with what’s available.