Keeping your UI fresh with Page Background Tasks

In this video I show the Page Background Tasks works in Business Central. This is a way to send time-consuming tasks to a background thread to avoid holding up the main thread and slowing down the user interface.

https://youtu.be/st8KoSQoCOY

In this video, Erik kicks off a mini-series on sessions and tasks in Business Central — the various ways you can run code simultaneously in a platform that historically was single-threaded. This first installment focuses on Page Background Tasks: what they are, how they work, and a real-world example from the eFocus SharePoint Connector app.

A Brief History: From Single-Threaded to Multi-Threaded

For those who grew up in the Dynamics NAV world, code execution has always been essentially single-threaded. You might have had multiple sessions running, or back in the old days you’d fire up multiple NAS instances, but within a single session your code never ran simultaneously. Business Central changes that with several new concepts that allow concurrent code execution. Page Background Tasks are one of the most useful additions.

What Is a Page Background Task?

A Page Background Task lets you offload time-consuming, read-only work to a background thread while keeping the page fully responsive. Erik demonstrates this with the eFocus SharePoint Connector: when navigating to a customer card, the SharePoint factbox initially appears empty, the page is fully interactive, and then — once the background task completes — the files appear.

Without a background task, the web service call to SharePoint would block the entire UI thread. The user would be stuck waiting. With a background task, the expensive call is “spun out” to a separate thread, and when it finishes, it fires a trigger back on the page with the results.

How to Enqueue a Background Task

The magic starts in the OnAfterGetCurrRecord trigger of your page (or page extension). You call CurrPage.EnqueueBackgroundTask with several parameters:

CurrPage.EnqueueBackgroundTask(TaskId, Codeunit::"Factbox Background Task", Parameters, 30000, PageBackgroundTaskErrorLevel::Warning);

Let’s break down each parameter:

  1. TaskId (Integer) — An identifier assigned by the system so you can reference the task later in completion/error triggers.
  2. Codeunit — The codeunit that will execute in the background thread.
  3. Parameters (Dictionary of [Text, Text]) — Key-value pairs you pass into the background codeunit. In Erik’s example, the only parameter needed is the SharePoint folder path associated with the customer.
  4. Timeout (Integer, milliseconds) — How long the task is allowed to run before being cancelled. Here it’s set to 30,000 ms (30 seconds).
  5. Error Level (PageBackgroundTaskErrorLevel) — What happens on the page if the background task errors out. Options are:
    • Error — Raises an error on the page.
    • Warning — Shows a notification on the page (non-blocking).
    • Ignore — Silently swallows the error.

Inside the Background Codeunit

The background codeunit uses the OnRun trigger. To retrieve the parameters that were passed in, you call Page.GetBackgroundParameters() — which admittedly feels a bit odd since you’re in a codeunit calling a Page method, but that’s the API:

trigger OnRun()
var
    Parameters: Dictionary of [Text, Text];
    Results: Dictionary of [Text, Text];
    JsonData: Text;
begin
    Parameters := Page.GetBackgroundParameters();

    // Step 1: Make the expensive web service call (read-only!)
    JsonData := GetFolderContentStep1(Parameters.Get('Folder'));

    // Package the result
    Results.Add('Data', JsonData);

    // Send result back to the calling page
    Page.SetBackgroundTaskResult(Results);
end;

The Read-Only Constraint

This is a critical point: the background thread has no write transaction. You can read from the database, but you cannot insert, modify, or delete records. This means you need to be strategic about what you put in the background task. In Erik’s case, he split his original function into two steps:

  • Step 1 (background thread) — Make the expensive SharePoint web service call and return the raw JSON.
  • Step 2 (main thread) — Process the JSON, populate temporary tables, and update the factbox UI.

The time-consuming part is the web service call, which is read-only by nature — a perfect fit for a background task.

Handling the Result on the Page

When the background task finishes, the platform calls one of two triggers on the calling page:

  • OnPageBackgroundTaskCompleted — Called on success, receives the results dictionary.
  • OnPageBackgroundTaskError — Called on failure, receives error information.

Before either trigger fires, the platform checks whether the current record is still the same as when the task was enqueued. If the user has navigated to a different record, the result is discarded and the task is effectively cancelled. This is an important safety mechanism.

trigger OnPageBackgroundTaskCompleted(TaskId: Integer; Results: Dictionary of [Text, Text])
begin
    // Grab the JSON from the results and process it
    FinishFill(Results.Get('Data'), Rec);
end;

trigger OnPageBackgroundTaskError(TaskId: Integer; ErrorCode: Text; ErrorText: Text; ErrorCallStack: Text; var IsHandled: Boolean)
begin
    // Display the error in the factbox, or handle gracefully
    ShowErrorInFactbox(ErrorText);
    IsHandled := true;
end;

The FinishFill function calls the second step of the split logic — processing the JSON into the temporary table that populates the factbox.

Where Page Background Tasks Work Best

Page Background Tasks were designed by Microsoft primarily for their own needs, and the two scenarios that are best supported are:

  • Populating factboxes on card pages (Card, Document)
  • Populating cue cards and similar summary data

Erik notes that he tried to get this working on list pages but it didn’t work well, because the current record is always changing as the user scrolls — which causes the background task to be cancelled repeatedly.

Important Considerations

  • Read-only operations only — No database writes in the background thread.
  • Runs on the same instance as the parent session.
  • Executes in its own (read-only) transaction — Isolated from the parent session’s transaction.
  • No UI operations — You’re in the background; no dialogs, confirms, or messages.
  • Automatic cancellation — If the calling page closes, the session ends, or the current record changes, the task is cancelled (it will never return a result, though when it actually stops executing is another discussion).
  • No session event records — It relies on the parent session’s event record; it’s a child session.
  • Concurrency limits — There’s a limit on the number of background tasks per session. If you fire off many tasks, some may have to wait in the queue for a free slot. That’s why the method is called Enqueue — you’re putting the task into a queue with no guarantee of immediate execution.
  • Not counted against the license — As is typical for child sessions.

The Lifecycle at a Glance

The official Microsoft documentation includes a helpful diagram of the lifecycle. Here’s a simplified version:

  1. Main thread: OnAfterGetCurrRecord fires → calls CurrPage.EnqueueBackgroundTask
  2. Background thread: Codeunit’s OnRun executes → calls Page.GetBackgroundParameters() to receive input → does work → calls Page.SetBackgroundTaskResult()
  3. Platform: Checks if the record is still the same → determines success or failure
  4. Main thread: OnPageBackgroundTaskCompleted or OnPageBackgroundTaskError fires → you process the result and update the UI

Real-World Impact

Erik emphasizes that this pattern is essential for apps like the SharePoint Connector that add functionality to every page. Without background tasks, every page load would be delayed by the time it takes to call SharePoint. With background tasks, the page feels exactly the same whether the SharePoint factbox is there or not — no added seconds, no added hundreds of milliseconds. The user experience remains snappy and responsive.

As Erik demonstrates at the end of the video (after removing the artificial 5-second sleep he added for demonstration purposes), the SharePoint data appears almost instantly — practically at the same time as the rest of the page — but it’s still asynchronous. It’s not making anything slower; it’s just making it non-blocking.

Conclusion

Page Background Tasks are a powerful tool for keeping your Business Central UI responsive while performing expensive operations like web service calls or heavy computations. The key takeaways are: split your logic into a read-only expensive part (background) and a write/UI part (main thread), use the dictionary-based parameter passing, and handle both success and error scenarios gracefully. This is the first video in Erik’s series on sessions and tasks — stay tuned for more on the other multithreading mechanisms available in Business Central.