This document describes a first example implementation of a plugin in the DataMigratePro system.
1. introduction
With DataMigratePro’s plug-in architecture, external functions can be integrated into the system in a modular fashion. The aim is extensibility without having to adapt the core code.
2. development of the plugin
The following example implements the interface IRelayPlugin. The action getprinter returns a list of 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 DataMigratePro.Plugins.dll must be copied to the subdirectory plugins.
3. business central integration
An AL page is provided to control the plugin, which takes over 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
The result is displayed in the Response field of the page after successful execution:

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