# Basic Plugin Overview Every workflow scheme needs basic operations - sending HTTP requests, notifying users by email, creating independent process instances, managing subprocesses, checking parameters, and restricting [commands](https://docs.workflowengine.io/get-started/concepts/command/) to specific roles. Without BasicPlugin, each of these requires a custom `IWorkflowActionProvider` or `IWorkflowRuleProvider` implementation. BasicPlugin solves this by registering [actions](https://docs.workflowengine.io/get-started/concepts/action/), conditions, and [rules](https://docs.workflowengine.io/get-started/concepts/rule/) with [WorkflowRuntime](https://docs.workflowengine.io/get-started/concepts/workflow-runtime/) through a single `runtime.WithPlugin(new BasicPlugin())` call, so you assign actions to [activities](https://docs.workflowengine.io/get-started/concepts/activity/) and conditions and rules to [transitions](https://docs.workflowengine.io/get-started/concepts/transition/) without writing custom providers. ## What BasicPlugin provides BasicPlugin is included in `OptimaJet.Workflow.Core` and does not require a separate NuGet package or license. Once registered, its actions, conditions, and rules are available for use in workflow schemes. ### In the Designer When you select an activity in the [Workflow Designer](https://docs.workflowengine.io/get-started/concepts/scheme/) and open its **Implementation** section, the available actions appear in a dropdown. BasicPlugin registers its actions so they show up in this dropdown alongside code actions defined in the scheme. The same applies to **Conditions** in transition settings and **Rules** in actor restrictions - BasicPlugin populates the dropdown lists with its registered capabilities. The Designer discovers registered actions, conditions, and rules through the `IWorkflowActionProvider` and `IWorkflowRuleProvider` interfaces at runtime. When you register a plugin, the runtime exposes its capabilities to the Designer API automatically - no additional configuration is needed. BasicPlugin also implements `ICustomActivityProvider`. During plugin registration, it creates a custom activity type for each non-excluded synchronous and asynchronous action. The Designer API returns these types to the **Elements** panel, where they appear on the **Activities** tab. Adding one to the scheme creates an activity that invokes the corresponding BasicPlugin action at runtime; the values configured in its form are stored in the activity annotations. This provides an alternative to adding the same action manually in **Implementation**. ### Available capabilities **Actions:** send HTTP requests, send emails, create independent process instances, set parameters, remove parameters, set activity, set state, execute commands on other processes, delete subprocesses, fill approvers by users, fill approvers by roles, clear approvers. **Conditions:** check all subprocesses completed, check HTTP request response, check approved by users, check approved by roles, check if process is finished, check if approval is complete, check parameter value, check if approvers exist. **Rules:** approver-based authorization (`Approver`), role-based authorization (`CheckRole`), and application-defined actor authorization (`Predefined`). The `FillApproversRoles` action, `IsApprovedByRoles` condition, and `CheckRole` rule require the `UsersInRoleAsync` delegate. When this delegate is not set, these capabilities are not registered and do not appear in the Designer dropdowns. Predefined actors are registered in application code and use the built-in `Predefined` rule. WorkflowRuntime adds their actor definitions to each applicable scheme. ## Register and configure BasicPlugin Register [BasicPlugin](https://api.workflowengine.io/core/OptimaJet.Workflow.Plugins/BasicPlugin/) after completing the base [WorkflowRuntime configuration](https://docs.workflowengine.io/get-started/concepts/workflow-runtime/) and before calling `runtime.StartAsync()`. The shortened example below focuses only on BasicPlugin delegates and registration. ```csharp filename="WorkflowInit.cs" using Microsoft.Extensions.DependencyInjection; using OptimaJet.Workflow.Core.Runtime; using OptimaJet.Workflow.Plugins; public class WorkflowInit { public async Task CreateRuntimeAsync( IServiceProvider services) { // --- Required: create the plugin (no delegates needed) --- var basicPlugin = new BasicPlugin(); // --- Optional: pick the features you need, remove the rest --- // Feature: role-based authorization // Required for: CheckRole rule, FillApproversRoles action, // IsApprovedByRoles condition var userRepository = services.GetRequiredService(); basicPlugin.UsersInRoleAsync = async (role, processInstance) => { var users = await userRepository.GetUsersInRoleAsync(role); return users.Select(u => u.Id.ToString()); }; // Feature: approval stages // Required for: FillApproversUsers with // GetUsersFrom = FromApproversInStage var approvalService = services.GetRequiredService(); basicPlugin.ApproversInStageAsync = async (stage, processInstance) => { var approvers = await approvalService.GetApproversAsync( processInstance.ProcessId, stage); return approvers.Select(a => a.IdentityId); }; // Feature: external state sync // Called when process becomes Idled or Finalized var documentService = services.GetRequiredService(); basicPlugin.UpdateDocumentStateAsync = async ( processInstance, stateName, localizedStateName) => { await documentService.UpdateStateAsync( processInstance.ProcessId, stateName); }; // --- Register and start --- // Additional WorkflowRuntime configuration is required before startup. var runtime = new WorkflowRuntime() .WithPlugin(basicPlugin); await runtime.StartAsync(); return runtime; } } ``` ## How BasicPlugin integrates with the runtime BasicPlugin subscribes to the `OnProcessStatusChangedAsync` runtime event. When a process transitions to `Idled` or `Finalized` status, and the `UpdateDocumentStateAsync` delegate is set, the plugin calls the delegate with the process instance, the current state name, and the localized state name. Use this to synchronize an external document status with the workflow state. The subscription is scoped: if the plugin was registered with a `schemes` filter, only processes belonging to those schemes trigger the callback. Subprocesses are ignored. ## Reference The tables below summarize the workflow-scheme actions, conditions, rules, and common configuration properties registered by BasicPlugin. They are not a complete list of its public .NET members. See the [BasicPlugin API reference](https://api.workflowengine.io/core/OptimaJet.Workflow.Plugins/BasicPlugin/) for constructors, properties, methods, and fields. ### Actions BasicPlugin registers actions that you can assign to any [activity](https://docs.workflowengine.io/get-started/concepts/activity/) in your workflow scheme. Table: BasicPlugin actions | Action | Purpose | |--------|---------| | `SetActivity` | Sets the current activity of the process directly | | `SetState` | Sets the process state string | | `SetParameter` | Writes a value to a process [parameter](https://docs.workflowengine.io/get-started/concepts/parameter/), supports expressions | | `RemoveParameter` | Deletes a parameter from the process | | `HTTPRequest` | Sends an HTTP GET or POST request and optionally stores the response | | `SendEmail` | Sends an email using the configured SMTP settings | | `CreateProcess` | Creates an independent [process instance](https://docs.workflowengine.io/get-started/concepts/process-instance/) with parameters | | `DeleteSubprocesses` | Removes all subprocesses of the current process | | `ExecuteCommand` | Executes a command on another process instance | | `FillApproversUsers` | Populates the approvers list with specific user IDs | | `FillApproversRoles` | Populates the approvers list with users from roles (requires `UsersInRoleAsync`) | | `ClearApprovers` | Resets every stored approver flag to `false` and clears `ActivityWithApprovers` | #### SetActivity action Sets the current activity of the process directly. | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `ActivityName` | string | yes | - | | `SetAfter` | `SetAfter` | yes | `AfterAction` | #### SetState action Sets the process state string. | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `StateName` | string | yes | - | | `SetAfter` | `SetAfter` | yes | `AfterAction` | | `ProcessId` | Guid | no | current process | #### SetParameter action Writes a value to a process parameter. With expression compilation enabled (the default), `Value` must contain a non-empty C# expression. To store an empty string, use the explicit C# string literal `\"\"` in the action JSON. | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `ParameterName` | string | yes | - | | `Value` | string | yes | - | | `ForRootProcess` | bool | no | `false` | #### RemoveParameter action Deletes a parameter from the process. | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `ParameterName` | string | no | `""` | | `ForRootProcess` | bool | no | `false` | #### HTTPRequest action Sends an HTTP GET or POST request and optionally stores the response. | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `Url` | string | yes | - | | `Post` | bool | no | `false` | | `ContentType` | `ContentTypeHeaderHTTP` | when `Post` is `true` | `Json` | | `Username` | string | no | - | | `Password` | string | no | - | | `Headers` | string | no | - | | `Parameters` | string | no | - | | `StoreResponse` | bool | no | `false` | | `ParameterName` | string | no | `HTTPRequest_Result` | | `ParameterPurpose` | `ParameterPurpose` | no | `Temporary` | | `AddProcessInstanceParameters` | bool | no | `true` | #### SendEmail action Sends an email using the configured SMTP settings. | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `To` | string | yes | - | | `Subject` | string | no | - | | `Body` | string | no | - | | `IsHTML` | bool | no | `false` | | `CcList` | JSON array | no | | | `BccList` | JSON array | no | | | `ReplyToList` | JSON array | no | | | `MailServer` | string | no | plugin setting | | `MailServerPort` | int | no | plugin setting | | `MailServerFrom` | string | no | plugin setting | | `MailServerLogin` | string | no | plugin setting | | `MailServerPass` | string | no | plugin setting | | `MailServerSsl` | bool | no | plugin setting | #### CreateProcess action Creates an independent process instance from the specified scheme and parameters. `CreateProcess` does not assign parent or subprocess metadata; fork transitions create child subprocesses. | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `Scheme` | string | yes | - | | `ProcessCreationParameters` | string (JSON) | yes | - | | `ProcessId` | Guid | no | auto-generated | #### ExecuteCommand action Executes a command on another process instance. | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `CommandName` | string | yes | - | | `ProcessId` | Guid | yes | - | #### FillApproversUsers action Populates the approvers list with specific user IDs. | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `Users` | string | when `GetUsersFrom` is `FromParameters` | - | | `Separator` | string | when `GetUsersFrom` is `FromParameters` | Designer supplies `,`; runtime has no default | | `RequiredApprovalsNumber` | int | no | `0` | | `GetUsersFrom` | `GetUsersFrom` | no | `FromParameters` | | `StageName` | string | when `GetUsersFrom` is `FromApproversInStage` | - | `FillApproversUsers` requires `Separator` at runtime when `GetUsersFrom` is `FromParameters`. The Designer supplies `,`, but the action has no runtime default when the parameter is omitted. `FromApproversInStage` requires the `ApproversInStageAsync` delegate. #### FillApproversRoles action Populates the approvers list with users from roles. | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `Roles` | string | yes | - | | `Separator` | string | yes | `,` | | `RequiredApprovalsNumber` | int | no | `0` | Requires `UsersInRoleAsync` delegate. #### DeleteSubprocesses action Removes all subprocesses of the current process. No parameters. #### ClearApprovers action Keeps every identity in the `Approvers` parameter and resets each stored approval flag to `false`. It also sets `ActivityWithApprovers` to `null`. The action has no parameters. ### Conditions BasicPlugin registers conditions that evaluate to `true` or `false` and control whether a [transition](https://docs.workflowengine.io/get-started/concepts/transition/) fires. Table: BasicPlugin conditions | Condition | Returns true when | |-----------|-------------------| | `CheckAllSubprocessesCompleted` | All [subprocesses](https://docs.workflowengine.io/get-started/concepts/subprocess/) of the current process have completed | | `IsProcessFinish` | The process status is `Finalized` | | `IsApprovedByUsers` | Every specified user appears as executor or actor in non-Reverse process history | | `IsApprovedByRoles` | Every user resolved from the roles appears in non-Reverse history (requires `UsersInRoleAsync`) | | `CheckHTTPRequest` | An HTTP request response matches a comparison condition | | `IsApproveComplete` | The required number of approval flags are `true`, or all flags are `true` when the threshold is `0` | | `CheckParameter` | A process [parameter](https://docs.workflowengine.io/get-started/concepts/parameter/) matches a given value using a comparison operator | | `CheckApproversExist` | At least one identity resolves from `Allow` restrictions on matching command transitions | #### CheckParameter condition Checks whether a process parameter matches a value using a comparison operator. | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `ParameterName` | string | no | - | | `CompareType` | `CompareType` | no | `Equal` | | `Value` | string | no | - | | `Separator` | string | no | `,` | | `ForRootProcess` | bool | no | `false` | Supported `CompareType` values: `Equal`, `NotEqual`, `Contains`, `StartWith`, `EndWith`, `NotContains`, `StartAndEndWith`, `NotStartWith`, `NotEndWith`, `NotStartAndEndWith`, `Greater`, `Less`, `GreaterOrEqual`, `LessOrEqual`, `In`, `NotIn`. #### CheckAllSubprocessesCompleted condition Returns true when all subprocesses of the current process have completed. | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `Mode` | `CheckMode` | no | `AllSubprocesses` | `CheckMode` values: `AllSubprocesses` (only direct children), `AllSubprocessesAndParent` (includes parent process). #### IsProcessFinish condition Returns true when the process status is Finalized. | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `ProcessId` | Guid | no | current process | #### IsApprovedByUsers condition Returns true when every specified user appears as `ExecutorIdentityId` or `ActorIdentityId` in at least one process-history item whose `TransitionClassifier` is not `Reverse`. The condition does not require the history item to use a command trigger. | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `Users` | string | yes | - | | `Separator` | string | no | `,` | #### IsApprovedByRoles condition Resolves every specified role through `UsersInRoleAsync`, then returns true only when every resolved user appears as `ExecutorIdentityId` or `ActorIdentityId` in at least one process-history item whose `TransitionClassifier` is not `Reverse`. The condition does not require the history item to use a command trigger. | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `Roles` | string | yes | - | | `Separator` | string | no | `,` | Requires `UsersInRoleAsync` delegate. #### CheckHTTPRequest condition Sends an HTTP request and compares the response against a condition. | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `Url` | string | yes | - | | `Post` | bool | no | `false` | | `ContentType` | `ContentTypeHeaderHTTP` | when `Post` is `true` | `Json` | | `Username` | string | no | - | | `Password` | string | no | - | | `Headers` | string | no | - | | `Parameters` | string | no | - | | `StoreResponse` | bool | no | `false` | | `ParameterName` | string | no | `HTTPRequest_Result` | | `ParameterPurpose` | `ParameterPurpose` | no | `Temporary` | | `AddProcessInstanceParameters` | bool | no | `true` | | `ResultFieldName` | string | no | - | | `ResultFieldValue` | string | no | `true` | | `CompareType` | `CompareType` | no | `Equal` | | `Separator` | string | no | `,` | #### IsApproveComplete condition Reads the `Approvers` process parameter and returns its approval state. When `RequiredApprovalsNumber` is greater than `0`, the condition returns `true` after at least that many stored flags become `true`. When the threshold is `0`, every stored approver flag must be `true`. The condition has no parameters and does not track a separate response or rejection state. #### CheckApproversExist condition Returns true when the runtime resolves at least one participant identity from Allow restrictions on command-triggered transitions that match the selected activity and transition classifiers. Actor definitions alone are insufficient: a matching actor whose rule resolves no identities does not satisfy the condition. | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `TransitionClassifier` | string | yes | `Direct, NotSpecified` | | `BeginningWithRoot` | bool | no | `false` | | `ActivityName` | string | no | current activity | `TransitionClassifier` accepts `NotSpecified`, `Direct`, and `Reverse`. Separate multiple values with a comma followed by one space. ### Rules BasicPlugin provides rules that restrict which identities can execute a [command](https://docs.workflowengine.io/get-started/concepts/command/). Rules are referenced by **actors**, which are part of **restrictions** on [transitions](https://docs.workflowengine.io/get-started/concepts/transition/) that have a command trigger. When a user executes a command, the runtime checks the restrictions on the matching transition by calling the rule provider to determine which identities satisfy the rule. `Approver` authorizes the current identity only while it is present in the process's `Approvers` parameter with an approval flag of `false`. `RuleGetApprovers` calls `GetAvailiableApprovers`, which filters out identities whose flag is already `true`, so an approver who has already approved is no longer returned for authorization. The parameter is populated by `FillApproversUsers` or `FillApproversRoles`. `CheckRole` checks whether the current identity belongs to a named role. This rule requires the `UsersInRoleAsync` delegate to resolve role membership from your application's data store. When `UsersInRoleAsync` is `null`, the `CheckRole` rule is not registered. For `Approver` and `CheckRole`, create actors in the workflow scheme that reference the rule name, then add restrictions to command-triggered transitions that reference those actors. #### Predefined actors The `Predefined` rule authorizes actors registered in application code. WorkflowRuntime injects an actor definition for each applicable registration and uses the actor name as the rule parameter. Table: Predefined actor registration API | Member | Purpose | |--------|---------| | `WithActor(actor, schemes)` | Adds one actor. Omit `schemes` or pass an empty list to make it available to all schemes; otherwise, it is limited to the supplied scheme codes. Use this method before registering BasicPlugin. | | `WithActors(actors, schemes)` | Adds multiple actors with the same all-schemes or scheme-specific behavior as `WithActor`. Use this method before registering BasicPlugin. | | `PredefinedActorProvider` | Provides thread-safe `IActorProvider` operations for reading, replacing, adding, and removing actor collections grouped by scheme code. | `CheckPredefinedActorAsync` determines whether one identity satisfies the predefined actor named by the rule parameter. `GetPredefinedIdentitiesAsync` returns all identity IDs that satisfy that actor. Configure both delegates when the application uses both identity checks and participant enumeration. `Predefined` is excluded from ordinary Designer rule choices, but it remains registered for runtime execution. Runtime authorization uses the full rule catalog, including excluded rules, so the generated actor definitions can invoke `Predefined`. When a transition has multiple Allow restrictions, the default `AllowConcatenationType="And"` requires the identity to satisfy every Allow rule. Set `AllowConcatenationType="Or"` on the transition to accept an identity that satisfies any Allow rule. ### Configuration properties Table: BasicPlugin configuration properties | Property | Type | Default | Description | |----------|------|---------|-------------| | `Setting_Mailserver` | `string` | `""` | SMTP server hostname or IP address | | `Setting_MailserverPort` | `int` | `25` | SMTP port number | | `Setting_MailserverFrom` | `string` | `""` | Sender email address | | `Setting_MailserverLogin` | `string` | `""` | SMTP authentication username | | `Setting_MailserverPassword` | `string` | `""` | SMTP authentication password | | `Setting_MailserverSsl` | `bool` | `true` | Enable SSL/TLS for SMTP | | `Setting_DontCompileExpressions` | `bool` | `false` | Compatibility switch for `SetParameter` and `CreateProcess` expressions | | `RequestHeaders` | `Dictionary` | empty | Headers added to `DefaultRequestHeaders` for all HTTP actions | | `PredefinedActorProvider` | `IActorProvider` | empty | Thread-safe predefined actor collections grouped by scheme code | | `CheckPredefinedActorAsync` | `Delegate` | `null` | Checks whether one identity satisfies the predefined actor named by the rule parameter | | `GetPredefinedIdentitiesAsync` | `Delegate` | `null` | Returns the identity IDs that satisfy the predefined actor named by the rule parameter | | `UsersInRoleAsync` | `Delegate` | `null` | Resolves users belonging to a role. Required for `CheckRole`, `FillApproversRoles`, `IsApprovedByRoles` | | `ApproversInStageAsync` | `Delegate` | `null` | Resolves approvers for a stage. Used by `FillApproversUsers` when `GetUsersFrom` is `FromApproversInStage` | | `UpdateDocumentStateAsync` | `Delegate` | `null` | Called when the process transitions to Idled or Finalized status | | `GetApproverIdentityId` | `Delegate` | `null` | Converts a user identifier to an identity ID for the approvers list | `Setting_DontCompileExpressions` is obsolete and intended only for compatibility, but it still affects behavior. When set to `true`, `SetParameter` uses the action's string value without compiling it as an expression, and `CreateProcess` parses or deserializes parameter values instead of evaluating them as expressions. ## See also - [HTTP Requests](https://docs.workflowengine.io/plugins/basic-plugin/http-requests/): Call external APIs from your workflow and validate responses. - [Sending Emails](https://docs.workflowengine.io/plugins/basic-plugin/sending-emails/): Notify users at specific workflow stages via SMTP. - [Managing Subprocesses](https://docs.workflowengine.io/plugins/basic-plugin/managing-subprocesses/): Check whether child subprocesses created by fork transitions have completed, or delete all child subprocesses during cleanup. - [Managing Parameters](https://docs.workflowengine.io/plugins/basic-plugin/managing-parameters/): Store, delete, and branch on parameter values. - [Process Control](https://docs.workflowengine.io/plugins/basic-plugin/process-control/): Jump between activities and control process state. - [Parallel Approval](https://docs.workflowengine.io/plugins/basic-plugin/parallel-approval/): Set up multi-user approval without explicit branches. - [Role-Based Authorization](https://docs.workflowengine.io/plugins/basic-plugin/role-based-authorization/): Restrict commands to users in specific roles. ## Frequently asked questions **What does BasicPlugin add to Workflow Engine?** BasicPlugin adds actions, conditions, and rules to WorkflowRuntime. These cover common operations - HTTP requests, email, independent process creation, subprocess management, parameter manipulation, and role-based authorization - without writing custom action or rule providers. **Do I need to set all delegates on BasicPlugin?** No. Only set the delegates for the capabilities you use. If you do not use role-based authorization, leave `UsersInRoleAsync` unset and the `CheckRole` rule, `FillApproversRoles` action, and `IsApprovedByRoles` condition are excluded automatically. **Can I use BasicPlugin actions without its rules?** Yes. Actions and rules are independent. You can use `SendEmail`, `HTTPRequest`, or any other action without configuring any rule delegates. **How do I configure SMTP for the SendEmail action?** Set `Setting_Mailserver`, `Setting_MailserverPort`, `Setting_MailserverFrom`, `Setting_MailserverLogin`, `Setting_MailserverPassword`, and `Setting_MailserverSsl` on the BasicPlugin instance before registering it. The `SendEmail` action can also override these per-call.