# Action An action is named C# business logic that Workflow Engine executes from an [activity](https://docs.workflowengine.io/get-started/concepts/activity/) implementation while it runs a [process instance](https://docs.workflowengine.io/get-started/concepts/process-instance/). Actions connect a [scheme](https://docs.workflowengine.io/get-started/concepts/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](https://docs.workflowengine.io/images/get-started/concepts/action/DocumentApproval-action.png) ```xml filename="DocumentApproval.xml" {11-13} ``` 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: ```xml reviewers@example.com ``` ## 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. ```csharp filename="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("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 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 GetActions(string schemeCode, NamesSearchType searchType) => ["NotifyReviewers", "SendEmail"]; public List 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](https://docs.workflowengine.io/get-started/concepts/condition/) as well. Register the provider when configuring Workflow Engine: ```csharp 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](https://docs.workflowengine.io/get-started/concepts/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: ```csharp 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 - [Transition](https://docs.workflowengine.io/get-started/concepts/transition/): Transitions select target activities whose implementations contain actions. - [Parameter](https://docs.workflowengine.io/get-started/concepts/parameter/): Parameters carry process data that actions can read and update. - Call Custom Assembly Code: Implement and register an action provider for application code. - Configure WorkflowRuntime: Configure providers, Code Actions, and application assemblies on WorkflowRuntime. ## 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.