This document describes a first sample implementation of a plugin in the DataMigratePro system.
1. Introduction
With the plugin architecture of DataMigratePro, external functions can be integrated into the system in a modular way. The goal is extensibility without changing the core code.
2. Development of the plugin
The following example implements the IRelayPlugin interface. The getprinter action returns a list of the locally installed printers:
using System;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Drawing.Printing;
using DataMigratePro.Plugins;
namespace GetPrinterPlugin
{
public class GetPrinterPlugin : IRelayPlugin
{
public string ActionName => "getprinter";
public async Task<string> ExecuteAsync(string base64Data)
{
await Task.Yield(); // simulate async
string decodedInput = Encoding.UTF8.GetString(Convert.FromBase64String(base64Data));
var printers = new List<string>();
foreach (string printer in PrinterSettings.InstalledPrinters)
{
printers.Add(printer);
}
var result = new
{
action = ActionName,
input = decodedInput,
printers = printers
};
return System.Text.Json.JsonSerializer.Serialize(result, new System.Text.Json.JsonSerializerOptions { WriteIndented = true });
}
}
}🔧 Note: the plugin DLL and the DataMigratePro.Plugins.dll must be copied into the plugins subdirectory.
3. Business Central Integration
An AL page is provided for controlling the plugin; it handles the call and displays the result.
page 50100 "Relay Result Viewer"
{
PageType = Card;
Caption = 'Relay Result Viewer';
ApplicationArea = All;
UsageCategory = Administration;
layout
{
area(content)
{
field("ActionText"; ActionText) { ApplicationArea = All; }
field("JSON (Raw)"; RawJsonText) { ApplicationArea = All; MultiLine = true; }
field("Response"; ResultText) { ApplicationArea = All; Editable = false; MultiLine = true; }
field("Info"; InfoText) { ApplicationArea = All; Editable = false; Style = Attention; StyleExpr = true; }
}
}
actions
{
area(Processing)
{
group(Action)
{
action(SendToRelay)
{
Caption = 'Send to Azure Relay';
Image = ExecuteBatch;
ApplicationArea = All;
Promoted = true;
PromotedCategory = Process;
PromotedIsBig = true;
trigger OnAction()
var
Sender: Codeunit "Azure Relay Sender IOI";
FullJson: Text;
EncodedMessage: Text;
begin
Base64Data := ToBase64(RawJsonText);
FullJson := '{"action":"' + ActionText + '","data":"' + Base64Data + '"}';
EncodedMessage := ToBase64(FullJson);
ResultText := Sender.SendMessage(EncodedMessage);
end;
}
}
}
}
trigger OnOpenPage()
begin
ActionText := 'getprinter';
RawJsonText := '{}';
InfoText :=
'This tool sends actions to Azure Relay. ' +
'The data will be base64 encoded and wrapped into a JSON structure like: ' +
'{"action":"...","data":"..."}, then encoded again before sending.';
end;
var
ActionText: Text;
RawJsonText: Text;
Base64Data: Text;
ResultText: Text;
InfoText: Text;
local procedure ToBase64(InputText: Text): Text
var
TempBlob: Codeunit "Temp Blob";
Base64Convert: Codeunit "Base64 Convert";
OutStr: OutStream;
InStr: InStream;
begin
TempBlob.CreateOutStream(OutStr, TextEncoding::UTF8);
OutStr.WriteText(InputText);
TempBlob.CreateInStream(InStr, TextEncoding::UTF8);
exit(Base64Convert.ToBase64(InStr));
end;
}4. Sample output
After successful execution, the result is displayed in the Response field of the page:

5. Conclusion
This plugin shows how flexibly and modularly DataMigratePro can be extended. This architecture allows new functions to be developed, tested and operated in isolated modules.
