The idea behind these page background tasks ist as genius as it is simple. Let’s load intensive data in the background to not block the UI and keep it responsive. To achieve this, a background session could be started using CurrPage.EnqueueBackgroundTask which returns a unique Task-ID. The moment this background task is executed successfully, it raises an event OnPageBackgroundTaskCompleted, on which we check the responded Task ID against. If the Task ID of the response event matches our saved Task ID we can process the data as it is the result we’re listening to.
Important: Page background sessions must not change data! They are read-only!
Background Task Flow
A background task is a multithread operation between the parent and child sessions. The following diagram illustrates the flow of a background task. In the illustration, the threads start in the order: THREAD A, THREAD B, THREAD C.
This example has no specific task. Its intention is to show the pattern only.
We start the pbt defining the codeunit and some additional parameters.
//Create a global var to save our started Task ID var WaitTaskId: Integer; //Then trigger the background task trigger OnAfterGetRecord() var TaskParameters: Dictionary of [Text, Text]; begin // Add as many key-value pairs to the dictionary as you want TaskParameters.Add('MyPrimaryKey1', Rec."Primary Key Field 1"); TaskParameters.Add('MyPrimaryKey2', Rec."Primary Key Field 2"); //Enqueues the page background task and save the Task ID in our global WaitTaskId var CurrPage.EnqueueBackgroundTask(WaitTaskId, Codeunit::"Page Background Runner", TaskParameters); end;
Now the background session will be executed while the UI stays fully responsible. The background task itself must be a codeunit that could be parametrized however you want through the dictionary as seen above.
Important: Background sessions are automatically closed when the record is changed!
//Our Page Background Tasks codeunit trigger OnRun() var Result: Dictionary of [Text, Text]; begin //This might be a check of the params if not Evaluate(ContainerName, Page.GetBackgroundParameters().Get('MyPrimaryKey1')) then Error('Mandatory parameter not found'); if not Evaluate(FileIdentifier, Page.GetBackgroundParameters().Get('MyPrimaryKey2')) then Error('Mandatory parameter not found'); //Do something with your record, call a webservice or whatever //... //Write back whatever data you like Result.Add('ProcessingDone', 'true'); //Send back to the OnPageBackgroundTaskCompleted event Page.SetBackgroundTaskResult(Result); end;
Now that the response event is activated we can process the response.
//Here comes our response trigger OnPageBackgroundTaskCompleted(TaskId: Integer; Results: Dictionary of [Text, Text]) var IsUpdated: Boolean; begin //Am i the task-id my ui is waiting for? if (TaskId = WaitTaskId) then if Results.ContainsKey('ProcessingDone') then if Evaluate(IsUpdated, Results.Get('ProcessingDone')) then begin //do whatever you like end, end; //Sure, there might also be some errors trigger OnPageBackgroundTaskError(TaskId: Integer; ErrorCode: Text; ErrorText: Text; ErrorCallStack: Text; var IsHandled: Boolean) begin //Do something. f.ex. show a notification //... end;
For sure you could also stop the background session if you want using Page.CancelBackgroundTask(TaskId: Integer).
I think page backgound tasks are an important step in the right direction to bring the webclient forward and differentiate it from the fullclient. In particular long loading data, webservices or the additional use of background tasks bring new possibilities to build rich interfaces… not at the expense of performance!