Workflow API Core
The Core component of the Workflow API manages other components and building the API using an internal builder based on ASP.NET minimal API.
The Core component does not implement endpoint functionality, so be sure to include one of the Data components.
Quick Setup
The Core component is included in the base NuGet package OptimaJet.Workflow.Api
for .NET 8.0. You can add it to your project with the following command:
dotnet add package OptimaJet.Workflow.Api
The Core component is integrated into an ASP.NET application using three extension methods. The first method adds the necessary services and allows options configuration:
- Quick
- Detailed
- Explicit Tenant
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddWorkflowApi(new WorkflowApiOptionsSetup {
SetupCore = options =>
{
// Configure the Workflow Engine API Core options.
options.LicenseKey = "V2-TRIAL-VFJJQUw6MDguMjAuMjAyNTpleUpTWlhOMGNtbGpkR2x2Ym5NaU9uc2lVM1J5YVdOMFEyaGxZMnNpT21aaGJITmxMQ0pOWVhoT2RXMWlaWEpQWmtGamRHbDJhWFJwWlhNaU9qRXdMQ0pOWVhoT2RXMWlaWEpQWmxSeVlXNXphWFJwYjI1eklqb3hNQ3dpVFdGNFRuVnRZbVZ5VDJaRGIyMXRZVzVrY3lJNk5Td2lUV0Y0VG5WdFltVnlUMlpUWTJobGJXVnpJam94TENKTllYaE9kVzFpWlhKUFpsUm9jbVZoWkhNaU9qRXNJa0ZqZEdsMlpVUnBjbVZqZEc5eWVTSTZabUZzYzJVc0lrSnlZVzVrYVc1bklqb2lRbkpoYm1ScGJtY2lMQ0pYYjNKclpteHZkMFZ1WjJsdVpVRndhU0k2SW5SeWRXVWlmU3dpUTNWemRHOXRVbVZ6ZEhKcFkzUnBiMjRpT25SeWRXVjk6bE1iTHBleFplMXk3ZEw5NHVLNm1EZWpkbzVOalZPd1JZZjIvbUZIZmlCb1RiMjdUWFBvQ1gyN1NFeWNiMm1SLzNSckhkWUlWMy9zaG1VWTgvRjZVQk5iQlhMK0lFYmFIYVJ0YVNiVDlldmI1ZWVYaEF4a1RmNmdCVVpiWHBwR3JuY09wNEJIV2dPR2RZZXJSTFNxc0Y3RlRxbGE3Z3RwbkpHTy9IdWJHZWlzPQ==";
},
SetupSecurity = options =>
{
// Configure the Workflow Engine API Security options.
options.DisableSecurity = true;
},
SetupWorkflowRuntime = options =>
{
// Configure the Workflow Engine Runtime options.
options.ConnectionString = "Data Source=:memory:";
}
});
As alternative, you can use three separate extension methods.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddWorkflowApiCore(options =>
{
// Configure the Workflow Engine API Core options.
options.LicenseKey = "V2-TRIAL-VFJJQUw6MDguMjAuMjAyNTpleUpTWlhOMGNtbGpkR2x2Ym5NaU9uc2lVM1J5YVdOMFEyaGxZMnNpT21aaGJITmxMQ0pOWVhoT2RXMWlaWEpQWmtGamRHbDJhWFJwWlhNaU9qRXdMQ0pOWVhoT2RXMWlaWEpQWmxSeVlXNXphWFJwYjI1eklqb3hNQ3dpVFdGNFRuVnRZbVZ5VDJaRGIyMXRZVzVrY3lJNk5Td2lUV0Y0VG5WdFltVnlUMlpUWTJobGJXVnpJam94TENKTllYaE9kVzFpWlhKUFpsUm9jbVZoWkhNaU9qRXNJa0ZqZEdsMlpVUnBjbVZqZEc5eWVTSTZabUZzYzJVc0lrSnlZVzVrYVc1bklqb2lRbkpoYm1ScGJtY2lMQ0pYYjNKclpteHZkMFZ1WjJsdVpVRndhU0k2SW5SeWRXVWlmU3dpUTNWemRHOXRVbVZ6ZEhKcFkzUnBiMjRpT25SeWRXVjk6bE1iTHBleFplMXk3ZEw5NHVLNm1EZWpkbzVOalZPd1JZZjIvbUZIZmlCb1RiMjdUWFBvQ1gyN1NFeWNiMm1SLzNSckhkWUlWMy9zaG1VWTgvRjZVQk5iQlhMK0lFYmFIYVJ0YVNiVDlldmI1ZWVYaEF4a1RmNmdCVVpiWHBwR3JuY09wNEJIV2dPR2RZZXJSTFNxc0Y3RlRxbGE3Z3RwbkpHTy9IdWJHZWlzPQ==";
});
builder.Services.AddWorkflowApiSecurity(options =>
{
// Configure the Workflow Engine API Security options.
options.DisableSecurity = true;
});
builder.Services.AddWorkflowEngineRuntime(options =>
{
// Configure the Workflow Engine Runtime options.
options.ConnectionString = "Data Source=:memory:";
});
You can also configure the Workflow API in single-tenant mode by explicitly registering a tenant. The result will be the same as in the alternative examples. Keep in mind that tenants are always registered in the Workflow API, even in single-tenant mode.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddWorkflowApiCore(options =>
{
// Configure the Workflow Engine API Core options.
options.DefaultTenantId = WorkflowApiConstants.SingleTenantId;
options.LicenseKey = "V2-TRIAL-VFJJQUw6MDguMjAuMjAyNTpleUpTWlhOMGNtbGpkR2x2Ym5NaU9uc2lVM1J5YVdOMFEyaGxZMnNpT21aaGJITmxMQ0pOWVhoT2RXMWlaWEpQWmtGamRHbDJhWFJwWlhNaU9qRXdMQ0pOWVhoT2RXMWlaWEpQWmxSeVlXNXphWFJwYjI1eklqb3hNQ3dpVFdGNFRuVnRZbVZ5VDJaRGIyMXRZVzVrY3lJNk5Td2lUV0Y0VG5WdFltVnlUMlpUWTJobGJXVnpJam94TENKTllYaE9kVzFpWlhKUFpsUm9jbVZoWkhNaU9qRXNJa0ZqZEdsMlpVUnBjbVZqZEc5eWVTSTZabUZzYzJVc0lrSnlZVzVrYVc1bklqb2lRbkpoYm1ScGJtY2lMQ0pYYjNKclpteHZkMFZ1WjJsdVpVRndhU0k2SW5SeWRXVWlmU3dpUTNWemRHOXRVbVZ6ZEhKcFkzUnBiMjRpT25SeWRXVjk6bE1iTHBleFplMXk3ZEw5NHVLNm1EZWpkbzVOalZPd1JZZjIvbUZIZmlCb1RiMjdUWFBvQ1gyN1NFeWNiMm1SLzNSckhkWUlWMy9zaG1VWTgvRjZVQk5iQlhMK0lFYmFIYVJ0YVNiVDlldmI1ZWVYaEF4a1RmNmdCVVpiWHBwR3JuY09wNEJIV2dPR2RZZXJSTFNxc0Y3RlRxbGE3Z3RwbkpHTy9IdWJHZWlzPQ==";
});
builder.Services.AddWorkflowApiSecurity(options =>
{
// Configure the Workflow Engine API Security options.
options.DisableSecurity = true;
});
builder.Services.AddWorkflowEngineRuntimeTenants(new WorkflowEngineTenantCreationOptions
{
// Configure the Workflow Engine Runtime options.
TenantIds = [WorkflowApiConstants.SingleTenantId],
ConnectionString = "Data Source=:memory:"
});
This is just a sample. In a real application, the configuration would be stored in an appsettings.json
file.
The second method, located in the Data component, adds services with operation implementations based on the data provider you use for your Workflow Engine application. As an example, let's consider using SQLite, but you can choose any other provider. A complete list of providers and integration details can be found in the Data documentation. First, add the appropriate NuGet package:
dotnet add package OptimaJet.Workflow.Api.Sqlite
This version of SQLite may not be compatible with macOS on Apple Silicon processors.
Next, use the extension method to configure the data provider:
builder.Services.AddWorkflowApiSqlite();
The third extension method is applied to your HTTP pipeline, adding the necessary middleware and registering the built API based on the provided settings and connected components:
var app = builder.Build();
app.UseWorkflowApi();
app.Run();
That's it! In just three steps, you've integrated the Workflow API Core.
Authentication and authorization settings are handled by the separate Security component,
while DisableSecurity
is true all API operations will be entirely public.
Multi-Tenant Mode
In Quick Setup we covered how to configure the Workflow API in single-tenant mode. In that mode, the API works
with one tenant which identifier is WorkflowApiConstants.SingleTenantId
.
For most scenarios this is sufficient to run Workflow Engine, and you don’t need to think about tenants or other multi-tenant details. Single-tenant mode simply hides those details from you.
Configuration
In the Workflow API, a tenant is represented by a tuple of TenantId
, WorkflowRuntime
, and IWorkflowProvider
(a
database). A single IWorkflowProvider
can serve multiple WorkflowRuntime
instances, and each runtime can handle
requests from multiple tenants.
Tenants that differ only by TenantId
but are served by the same WorkflowRuntime
are called logical tenants.
Tenants served by different WorkflowRuntime
instances are called physical tenants.
To enable multi-tenant mode, use AddWorkflowEngineRuntimeTenants
instead of AddWorkflowEngineRuntime
. In it, you
provide a list of options describing the physical tenants to create. For example:
builder.Services.AddWorkflowEngineRuntimeTenants(
new WorkflowEngineTenantCreationOptions
{
// First physical tenant creation options.
TenantIds = ["MsSqlTenant1", "MsSqlTenant2"],
DataProviderId = PersistenceProviderId.Mssql,
ConnectionString = "Server=localhost,1433;Database=master;User Id=SA;Password=MyPassword;"
},
new WorkflowEngineTenantCreationOptions
{
// Second physical tenant creation options.
TenantIds = ["PostgresTenant1", "PostgresTenant2"],
DataProviderId = PersistenceProviderId.Postgres,
ConnectionString = "Host=localhost;Port=5432;Database=postgres;User Id=postgres;Password=MyPassword;"
}
);
//Don't forget to register the data providers you use.
builder.Services.AddWorkflowApiMssql();
builder.Services.AddWorkflowApiPostgres();
This example defines two physical tenants. The first serves the logical tenants MsSqlTenant1
and MsSqlTenant2
using
MS SQL Server data provider, and the second serves PostgresTenant1
and PostgresTenant2
using PostgreSQL.
Key options in WorkflowEngineTenantCreationOptions
:
TenantIds
— the list of logical tenant identifiers that will be handled by thisWorkflowRuntime
andIWorkflowProvider
(i.e., by this physical tenant).DataProviderId
— the identifier of the data provider used to create theIWorkflowProvider
. If omitted, one of the registered providers will be used. The selected provider must be registered as a Data component. Available IDs are listed inPersistenceProviderId
.ConnectionString
— the database connection string used to create theIWorkflowProvider
. You can define multiple physical tenants that use the same data provider but different connection strings.
The remaining options in WorkflowEngineTenantCreationOptions
let you fine-tune how WorkflowRuntime
and
IWorkflowProvider
are created.
Usage
When calling the API in multi-tenant mode, you can explicitly specify TenantId
via the
WorkflowApiConstants.TenantIdHeader
request header ("Workflow-Api-Tenant-ID"
). If the header is missing,
DefaultTenantId
is used, which by default equals WorkflowApiConstants.SingleTenantId
.
In multi-tenant mode, it’s recommended to set DefaultTenantId
to null
. This ensures that every API request must
explicitly provide a TenantId
; otherwise, the request is rejected with an error.
When a TenantId
is provided, the Workflow API resolves the physical tenant that serves the given logical tenant. The
request is then processed by the corresponding WorkflowRuntime
and IWorkflowProvider
.
In an ASP.NET application, you can also access all tenants via the IWorkflowApiTenantRegistry
service. If you are in
the context of an HTTP request, you can retrieve the current tenant with
IWorkflowApiTenantRegistry.GetHttpContextTenant
or via an extension method on IServiceProvider
.
public class MyController : ControllerBase
{
private readonly IWorkflowApiTenantRegistry _tenantRegistry;
public MyController(IWorkflowApiTenantRegistry tenantRegistry)
{
_tenantRegistry = tenantRegistry;
}
[HttpGet("my-endpoint")]
public IActionResult MyEndpoint()
{
var currentTenant = _tenantRegistry.GetHttpContextTenant(HttpContext);
WorkflowRuntime runtime = currentTenant.Runtime;
// Use currentTenant here...
return Ok();
}
}
Core Options
You can configure the Core component options using the WorkflowApiCoreOptions
record provided as ASP.NET
IOptions
in the service collection. Below is a table describing its properties:
Name | Type | Default | Description |
---|---|---|---|
BasePath | string | "workflow-api" | The root path to the Workflow Engine API endpoints. If an empty string is specified, endpoints will be accessible via the root path of your application. |
LicenseKey | string | "" | The Workflow Engine license key with the Workflow Engine API option enabled. If the key is not provided, the API will not start. |
DefaultTenantId | string? | WorkflowApiConstants.SingleTenantId | The default tenant ID to use when no tenant is specified in the request. If default tenant is null , requests without a tenant specified will be rejected. |
Workflow Runtime or Tenant Options
When configuring the Workflow Engine Runtime using AddWorkflowEngineRuntime
or AddWorkflowEngineRuntimeTenants
,
you can specify options for creating WorkflowRuntime
instances. These options are defined in the
WorkflowEngineRuntimeOptions
record. In single-tenant mode, you can provide these options as ASP.NET IOptions
in the service collection. Below is a table describing its properties:
Name | Type | Default | Description |
---|---|---|---|
TenantIds | string[] | [] | The unique tenant identifiers to create with specific runtime options. If no tenant identifiers are specified, the single tenant id WorkflowApiConstants.SingleTenantId will be used. |
RuntimeCreationOptions | RuntimeCreationOptions | new() | Options for configuring the Workflow Engine WorkflowRuntime runtime of the tenant. |
DataProviderId | string? | null | The identifier of the data & persistence provider to use for the tenant creation. This identifier is used to select the data provider from the list of registered providers. If not specified, the first found provider or null will be used. |
ConnectionString | string | "" | Specifies the connection string used by the data and persistence provider for tenant creation. |
WorkflowApiDataProviderOptions | WorkflowApiDataProviderOptions | new() | Configuration options for the tenant's data provider. |
WorkflowProviderCreationOptions | WorkflowProviderCreationOptions | new() | Options for configuring the Workflow Engine IWorkflowProvider persistence provider of the tenant. |
Properties of WorkflowApiDataProviderOptions
are described in the Data documentation.
Runtime Creation Options
The RuntimeCreationOptions
record allows you to configure the WorkflowRuntime
instance of a tenant. Below is a
table describing its properties:
Name | Type | Default | Description |
---|---|---|---|
RuntimeId | Guid | Guid.Empty | The unique identifier for the Workflow Engine runtime instance. |
PersistenceProviderFactory | Func<IWorkflowProvider?, IPersistenceProvider> | provider => provider ?? throw new DataProviderNotFoundException() | A factory method for creating an instance of IPersistenceProvider , serving as an interface for storing process data in the Workflow Engine runtime. The parameter provided to the factory is the default IWorkflowProvider provider specified when creating the tenant or null if no provider is specified. |
WorkflowBuilderFactory | Func<IWorkflowProvider?, IWorkflowBuilder> | provider => new WorkflowBuilder<XElement>(provider, new XmlWorkflowParser(), provider).WithDefaultCache() | A factory method for creating an instance of IWorkflowBuilder , serving as a workflow scheme parser for the Workflow Engine runtime. The parameter provided to the factory is the IWorkflowProvider provider specified when creating the tenant or null if no provider is specified. |
ConfigureWorkflowRuntime | Action<WorkflowRuntime> | _ => { } | A delegate used to configure the Workflow Engine runtime instance. Called after the IPersistenceProvider and IWorkflowBuilder have been registered. |
DisableMigrationsExecution | bool | false | If set to true , disables the execution of WorkflowRuntimeExtensions.RunMigrations(WorkflowRuntime) during the initialization of the WorkflowRuntime . |
DisableRuntimeAutoStart | bool | false | If set to true , prevents the WorkflowRuntimeConfigurationExtension.StartAsync() from automatically starting after initialization. |
IgnoreNotCompiledGlobalActionsOnStart | bool | false | If set to true , the Workflow Engine runtime will ignore any compilation errors that occur in global actions during its startup. |
Workflow Provider Creation Options
The WorkflowProviderCreationOptions
record allows you to configure the IWorkflowProvider
instance of a tenant.
Below is a table describing its properties:
Name | Type | Default | Description |
---|---|---|---|
DisableWritingProcessTransitionHistory | bool | false | If set to true , prevents the Workflow Engine from saving process transition history to the database. |
WriteSubprocessTransitionHistoryToRootProcess | bool | false | When enabled, writes the transition history of subprocesses directly into the root process transition history. |
IWorkflowApiTenantRegistry
Service for managing tenants in a multi-tenant Workflow Engine API setup.
Tenants
Returns
Type | Description |
---|---|
IReadOnlyCollection<IWorkflowApiTenant> | All registered tenants. |
Get(string id)
Get a tenant by its id.
Parameters
Name | Type | Description |
---|---|---|
id | string | The tenant id. |
Returns
Type | Description |
---|---|
IWorkflowApiTenant | The tenant instance. |
GetHttpContextTenantId()
Get the tenant id from the current HTTP context based on the provided header or default tenant id.
Returns
Type | Description |
---|---|
string | The tenant id. |
GetHttpContextTenant()
Get the tenant instance from the current HTTP context.
Returns
Type | Description |
---|---|
IWorkflowApiTenant | The tenant instance. |
GetHttpContextWorkflowRuntime()
Get the workflow runtime instance for the tenant identified in the current HTTP context.
Returns
Type | Description |
---|---|
WorkflowRuntime | The workflow runtime instance. |
IWorkflowApiTenant
Defines a tenant in a multi-tenant Workflow Engine API setup. In a single-tenant setup registered as a single instance
with WorkflowApiConstants.SingleTenantId
as its only id.
Ids
Returns
Type | Description |
---|---|
IReadOnlyCollection<string> | All logical tenant ids that map to this tenant instance. |
Runtime
Returns
Type | Description |
---|---|
WorkflowRuntime | The workflow runtime instance for this tenant. |