Skip to Content
Evaluate Get Started

Action

An action is named C# business logic that Workflow Engine executes from an activity implementation while it runs a process instance. Actions connect a scheme to application behavior such as sending emails, updating database records, or calling external services. Workflow Engine uses the NameRef value from an action reference to find an action with the same name in an action provider or among Code Actions.

How actions are defined in the scheme

Actions are referenced by name in the scheme XML. The Implementation section on an activity lists the actions that Workflow Engine executes during normal activity execution.

DocumentApproval scheme with Submit command and LogActivityEntry action

DocumentApproval.xml
<Process Name="DocumentApproval">    <Commands>        <Command Name="Submit"/>    </Commands>    <Activities>        <Activity Name="Draft" IsInitial="true">            <Designer X="100" Y="200"/>        </Activity>        <Activity Name="Review">            <Implementation>                <ActionRef Order="0" NameRef="LogActivityEntry"/>            </Implementation>            <Designer X="400" Y="200"/>        </Activity>    </Activities>    <Transitions>        <Transition Name="Submit_Draft_Review"                    From="Draft" To="Review"                    Classifier="Direct">            <Triggers>                <Trigger Type="Command" NameRef="Submit"/>            </Triggers>            <Conditions>                <Condition Type="Always"/>            </Conditions>            <Designer/>        </Transition>    </Transitions></Process>

Each ActionRef identifies an action by NameRef. Workflow Engine executes the references by ascending Order when it runs the activity's normal Implementation.

Actions can carry a parameter, configured as a child element of the action reference. The value is a string and often contains JSON for structured data. Use this to pass data to the action method without writing separate action implementations:

<Activity Name="Review">    <Implementation>        <ActionRef Order="0" NameRef="SendEmail">            <ActionParameter>reviewers@example.com</ActionParameter>        </ActionRef>    </Implementation></Activity>

How an action works

You can implement an action provider and register it with Workflow Engine at startup. The provider implements IWorkflowActionProvider; its execution methods receive the action name, the current process instance, the runtime, and an optional string parameter from the scheme.

EmailActionProvider.cs
using OptimaJet.Workflow.Core.Model;using OptimaJet.Workflow.Core.Runtime;public interface IEmailService{    Task SendAsync(string to, string body, CancellationToken token);}public class EmailActionProvider : IWorkflowActionProvider{    private readonly IEmailService _email;    public EmailActionProvider(IEmailService email)    {        _email = email;    }    public async Task ExecuteActionAsync(        string name,        ProcessInstance process,        WorkflowRuntime runtime,        string parameter,        CancellationToken token)    {        if (name == "NotifyReviewers")        {            var reviewers = process.GetParameter<string>("ReviewerEmails");            await _email.SendAsync(reviewers, "Review required", token);        }        if (name == "SendEmail")        {            await _email.SendAsync(parameter, "Action required", token);        }    }    public void ExecuteAction(        string name,        ProcessInstance process,        WorkflowRuntime runtime,        string parameter) { }    public Task<bool> ExecuteConditionAsync(        string name, ProcessInstance process,        WorkflowRuntime runtime, string parameter,        CancellationToken token) => Task.FromResult(false);    public bool ExecuteCondition(        string name, ProcessInstance process,        WorkflowRuntime runtime, string parameter) => false;    public bool IsActionAsync(string name, string schemeCode) => true;    public bool IsConditionAsync(string name, string schemeCode) => false;    public List<string> GetActions(string schemeCode, NamesSearchType searchType) =>        ["NotifyReviewers", "SendEmail"];    public List<string> GetConditions(string schemeCode, NamesSearchType searchType) =>        new();}

GetActions returns the names supplied by the provider. For a matching name, IsActionAsync tells Workflow Engine whether to call ExecuteAction or ExecuteActionAsync. The same interface also contains GetConditions, IsConditionAsync, ExecuteCondition, and ExecuteConditionAsync because an action provider can supply conditions as well.

Register the provider when configuring Workflow Engine:

runtime.WithActionProvider(new EmailActionProvider(emailService));

Without a scheme list, the provider is available to every scheme managed by the runtime. You can also call WithActionProvider more than once and pass a list of scheme codes to scope a provider. See Call Custom Assembly Code from Actions for a full provider setup.

When an action runs

Normal actions belong to an activity, not to a transition. When a transition passes its conditions, Workflow Engine selects the target activity and executes the actions in that activity's Implementation. The initial activity's implementation can also run when a new process starts, without an incoming transition.

An activity can separately define PreExecutionImplementation. During pre-execution simulation, Workflow Engine executes that list instead of the normal Implementation. Both lists contain ordered action references, and neither makes an action free of external side effects.

Code Actions as a scheme-specific alternative

In addition to implementing an action provider, you can define C# actions directly in the scheme's CodeActions section. A local Code Action belongs to that scheme and can be referenced by name from an activity implementation.

Code Action and expression compilation are enabled by default. Disable both when the application must not execute scheme-defined C# code:

runtime.DisableCodeActions();

Call EnableCodeActions() to enable both compilers again.

Workflow Engine compiles Code Actions at runtime. Register an application assembly only when a Code Action needs types from that assembly; the framework-agnostic setup guide shows that configuration. Code Actions run with access to the host process, so only trusted users should be able to edit them.

Marking a Code Action as global stores it in Workflow Engine global parameters instead of one scheme and makes it available across schemes.

Search priority for actions

The runtime can resolve an action name from a local Code Action, a global Code Action, or a registered provider. The default LocalGlobalProvider order checks those sources in that sequence. SetExecutionSearchOrder can select any of the six orders defined by ExecutionSearchOrder when duplicate names require a different priority.

See also

Frequently asked questions

What is an action in Workflow Engine?

An action is named C# business logic referenced from an activity implementation. Workflow Engine resolves the name to a provider action or Code Action and executes it when it runs that activity.

How do I register an action provider with Workflow Engine?

Implement the IWorkflowActionProvider interface and register an instance via runtime.WithActionProvider(provider) in the builder chain at startup. Route by action name inside the implementation.

Can I have multiple action providers for different schemes?

Yes. Call runtime.WithActionProvider(provider, [schemeCode1, schemeCode2]) to register a provider for specific schemes. A provider registered without a scheme list is considered for every scheme.

How does the runtime choose which action to use when the same name exists in multiple places?

The runtime searches local Code Actions, global Code Actions, and the registered provider in LocalGlobalProvider order by default. Use runtime.SetExecutionSearchOrder() to select a different order.