WorkflowHandlerRegistry220FDW
The workflow handler registry resolves IStepHandler220FDW implementations for mobile workflows. It acts as the bridge between a workflow's configuration (stored in the Mobile Workflow 220FDW table) and the AL codeunit that contains the step logic.
Overview
- Object type: Codeunit (73167889)
- Access: Public
- Namespace:
Aptean.Mesh.SDUI - Purpose: Resolves which codeunit handles the steps for a given mobile workflow
Aptean Mesh uses a service-locator pattern for workflow handlers, similar to how MobileRPCRegistry220FDW resolves RPC services. Each workflow record stores a Resolver Codeunit ID that identifies which codeunit implements IStepHandler220FDW. At runtime, the registry fires an integration event so that the matching codeunit can return itself as the handler.
Resolution Flow
Workflow Engine
│
├─► WorkflowHandlerRegistry220FDW.ResolveStepHandler(State)
│ │
│ ├─► Look up Mobile Workflow 220FDW record
│ │ using State.Bundle() + State.Workflow()
│ │
│ ├─► Read "Resolver Codeunit ID" from the record
│ │
│ └─► Fire OnResolveWorkflowHandler(CodeunitId, ...)
│ │
│ └─► Subscriber sets StepHandler := this
│
└─► Call StepHandler.IsStepRequired / HandleStep / UndoStep
Methods
ResolveStepHandler
procedure ResolveStepHandler(
State: Codeunit MobileRPCState220FDW
) StepHandler: Interface IStepHandler220FDW
Resolves the step handler for the workflow identified in the given state object.
Parameters:
| Name | Type | Direction | Description |
|---|---|---|---|
State | Codeunit MobileRPCState220FDW | value | The current RPC state. The registry reads State.Bundle() and State.Workflow() to look up the workflow record. |
Returns: Interface IStepHandler220FDW -- the resolved step handler implementation.
Errors:
| Condition | Error Message |
|---|---|
| Workflow record not found | Workflow '{WorkflowCode}' not found for App Bundle '{BundleId}'. Ensure the workflow is configured in Mobile Workflows. |
| No handler subscribed | No workflow handler found for workflow '{WorkflowCode}' (Resolver Codeunit ID: {CodeunitId}). Ensure the codeunit subscribes to OnResolveWorkflowHandler event. |
Integration Event
OnResolveWorkflowHandler
[IntegrationEvent(false, false)]
local procedure OnResolveWorkflowHandler(
CodeunitId: Integer;
var StepHandler: Interface IStepHandler220FDW;
var IsResolved: Boolean)
Fired by the registry when it needs to resolve a workflow handler. Subscribe to this event in your codeunit to register yourself as the handler for a specific codeunit ID.
Parameters:
| Name | Type | Direction | Description |
|---|---|---|---|
CodeunitId | Integer | value | The Resolver Codeunit ID from the Mobile Workflow 220FDW record. Compare this to your own Codeunit:: identifier. |
StepHandler | Interface IStepHandler220FDW | var | Set this to your codeunit instance (this) when the CodeunitId matches. |
IsResolved | Boolean | var | Set to true after assigning StepHandler. Check this first -- if another subscriber already resolved the handler, exit immediately. |
Registration Example
The following example shows how to register a custom workflow handler. This pattern is identical to the one used by the built-in ReceiptService220FDW.
codeunit 50100 "My Workflow Handler" implements IStepHandler220FDW
{
[EventSubscriber(ObjectType::Codeunit,
Codeunit::WorkflowHandlerRegistry220FDW,
OnResolveWorkflowHandler, '', false, false)]
local procedure ResolveMyHandler(
CodeunitId: Integer;
var StepHandler: Interface IStepHandler220FDW;
var IsResolved: Boolean)
begin
// Guard: another subscriber already resolved
if IsResolved then
exit;
// Guard: this event is not for our codeunit
if CodeunitId <> Codeunit::"My Workflow Handler" then
exit;
// Register ourselves as the handler
StepHandler := this;
IsResolved := true;
end;
// Implement IStepHandler220FDW methods...
procedure IsStepRequired(
var State: Codeunit MobileRPCState220FDW;
var ItemMgt: Codeunit MobileItemMgt220FDW;
WorkflowStep: Record "Mobile Workflow Step 220FDW"): Boolean
begin
// Step-type dispatch logic
exit(true);
end;
procedure HandleStep(
var State: Codeunit MobileRPCState220FDW;
var ItemMgt: Codeunit MobileItemMgt220FDW;
WorkflowStep: Record "Mobile Workflow Step 220FDW"): Boolean
begin
// Step execution logic
exit(true);
end;
procedure UndoStep(
var State: Codeunit MobileRPCState220FDW;
var ItemMgt: Codeunit MobileItemMgt220FDW;
WorkflowStep: Record "Mobile Workflow Step 220FDW"): Boolean
begin
// Step undo logic
exit(false);
end;
}
Workflow Configuration Tables
The registry depends on two tables that define which workflows exist and what steps they contain.
Mobile Workflow 220FDW
Stores the workflow definitions for each app bundle.
| Field | Type | Description |
|---|---|---|
App Bundle ID | Guid | Foreign key to the Mobile App Bundle 220FDW table. |
Workflow Code | Code[20] | Unique identifier for the workflow within the bundle (e.g., RECEIPT, PUTAWAY). |
Description | Text[100] | Human-readable description of the workflow's purpose. |
Resolver Codeunit ID | Integer | The codeunit that implements IStepHandler220FDW for this workflow. This is the ID passed to OnResolveWorkflowHandler. |
Primary key: App Bundle ID + Workflow Code
Mobile Workflow Step 220FDW
Stores the ordered steps within each workflow.
| Field | Type | Description |
|---|---|---|
App Bundle ID | Guid | Foreign key to the parent workflow's bundle. |
Workflow Code | Code[20] | Foreign key to the parent workflow. |
Sequence | Integer | Execution order within the workflow. Lower numbers execute first. Auto-assigned in increments of 10. |
Step Type | Enum StepType220FDW | The type of data to capture (Bin, Item, LotNumber, Quantity, etc.). |
Step Input Type | Enum StepInputType220FDW | The UI input control to display on the mobile device (Barcode, Numeric, DatePicker, Image, Choice, etc.). |
Instruction | Text[50] | The text prompt shown to the user on the mobile device. |
GS1 AI | Code[30] | GS1 Application Identifiers for barcode parsing, separated by semicolons (e.g., 01;02). |
Primary key: App Bundle ID + Workflow Code + Sequence
The step table also provides helper methods:
SetWorkflowFilters(BundleId, WorkflowCode)-- sets filters and sorts by sequence for iterationGetFirstSequence()-- returns the lowest sequence number in the current filterFindByStepType(StepType)-- positions the record on the first step matching the given type
Setup in Business Central
To wire a workflow to your handler codeunit:
- Open Mobile App Bundles and select your bundle
- Open Mobile Workflows from the bundle card
- Create a workflow record:
- Workflow Code -- e.g.,
MYWORKFLOW(must match the workflow code sent by the mobile client) - Resolver Codeunit ID -- e.g.,
50100(the object ID of yourIStepHandler220FDWcodeunit)
- Workflow Code -- e.g.,
- Open Workflow Steps from the workflow card and add steps in sequence:
- Set the Step Type (e.g., LotNumber, Quantity, Bin)
- Set the Step Input Type for the mobile UI control
- Optionally set an Instruction and GS1 AI identifiers
Dual Registration Pattern
Most Aptean Mesh service codeunits implement both IBCRPC220FDW (for RPC dispatch) and IStepHandler220FDW (for workflow steps) on the same codeunit. This means the codeunit subscribes to two registry events:
codeunit 50100 "My Service" implements IBCRPC220FDW, IStepHandler220FDW
{
// Register as an RPC service
[EventSubscriber(ObjectType::Codeunit,
Codeunit::MobileRPCRegistry220FDW,
OnResolveService, '', false, false)]
local procedure ResolveService(
CodeunitId: Integer;
var Service: Interface IBCRPC220FDW;
var IsServiceResolved: Boolean)
begin
if IsServiceResolved then exit;
if CodeunitId <> Codeunit::"My Service" then exit;
Service := this;
IsServiceResolved := true;
end;
// Register as a workflow handler
[EventSubscriber(ObjectType::Codeunit,
Codeunit::WorkflowHandlerRegistry220FDW,
OnResolveWorkflowHandler, '', false, false)]
local procedure ResolveWorkflowHandler(
CodeunitId: Integer;
var StepHandler: Interface IStepHandler220FDW;
var IsResolved: Boolean)
begin
if IsResolved then exit;
if CodeunitId <> Codeunit::"My Service" then exit;
StepHandler := this;
IsResolved := true;
end;
// IBCRPC220FDW implementation
procedure RPC(var State: Codeunit MobileRPCState220FDW) ResponseJson: JsonObject
begin
case State.Method() of
'Initialize':
Initialize(State);
'HandleWorkFlow':
HandleWorkFlow(State);
'UndoStep':
ProcessUndoStep(State);
end;
ResponseJson := State.Serialize();
end;
// IStepHandler220FDW implementation
procedure IsStepRequired(
var State: Codeunit MobileRPCState220FDW;
var ItemMgt: Codeunit MobileItemMgt220FDW;
WorkflowStep: Record "Mobile Workflow Step 220FDW"): Boolean
begin
// ...
end;
procedure HandleStep(
var State: Codeunit MobileRPCState220FDW;
var ItemMgt: Codeunit MobileItemMgt220FDW;
WorkflowStep: Record "Mobile Workflow Step 220FDW"): Boolean
begin
// ...
end;
procedure UndoStep(
var State: Codeunit MobileRPCState220FDW;
var ItemMgt: Codeunit MobileItemMgt220FDW;
WorkflowStep: Record "Mobile Workflow Step 220FDW"): Boolean
begin
// ...
end;
}
In this pattern, the RPC method's 'HandleWorkFlow' branch typically calls WorkflowHandlerRegistry220FDW.ResolveStepHandler(State) to obtain the handler, then iterates through the workflow steps calling IsStepRequired, HandleStep, and UndoStep as needed.
See Also
- IStepHandler220FDW -- the interface contract for workflow step handlers
- IBCRPC220FDW -- the RPC service interface, often implemented on the same codeunit
- MobileRPCRegistry220FDW -- the RPC service registry (analogous pattern)
- MobileRPCState220FDW -- request parsing, state management, and response building
- Enums --
StepType220FDWandStepInputType220FDWreference