### ElsaScript Workflow Example Source: https://github.com/elsa-workflows/elsa-core/blob/main/src/modules/Elsa.Dsl.ElsaScript/README.md Demonstrates a basic ElsaScript workflow with 'use' statements, variable declaration, and activity invocation. ```ElsaScript use Elsa.Activities.Console; use expressions js; workflow "HelloWorld" { var greeting = "Hello"; WriteLine(=> greeting + " World"); WriteLine("Great to meet you!"); } ``` -------------------------------- ### Manual Integration Test with IWorkflowRunner Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/qa/test-guidelines.md Demonstrates manual setup for integration testing a simple workflow using IWorkflowRunner. Requires explicit service provider setup. ```csharp [Fact] public async Task Should_Execute_Workflow() { // Arrange var services = new TestApplicationBuilder(testOutputHelper).Build(); await services.PopulateRegistriesAsync(); var runner = services.GetRequiredService(); var workflow = Workflow.FromActivity(new WriteLine("Hello")); // Act var result = await runner.RunAsync(workflow); // Assert Assert.Equal(WorkflowStatus.Finished, result.WorkflowState.Status); } ``` -------------------------------- ### Programmatic workflow instance management with IWorkflowClient Source: https://context7.com/elsa-workflows/elsa-core/llms.txt Manages workflow instances programmatically using the IWorkflowClient. Retrieve a client from IWorkflowRuntime.CreateClientAsync(). This example shows how to start and cancel workflow instances. ```csharp using Elsa.Workflows.Runtime; using Elsa.Workflows.Runtime.Messages; public class OrderService(IWorkflowRuntime workflowRuntime) { public async Task StartOrderWorkflowAsync(string definitionId, object orderData, CancellationToken cancellationToken = default) { // Create a client for a new instance var client = await workflowRuntime.CreateClientAsync(cancellationToken); var createRequest = new CreateWorkflowInstanceRequest { WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(definitionId), CorrelationId = $"order-{Guid.NewGuid()}", Input = new Dictionary { ["OrderData"] = orderData } }; var runRequest = new RunWorkflowInstanceRequest(); var response = await client.CreateAndRunInstanceAsync( new CreateAndRunWorkflowInstanceRequest { CreateRequest = createRequest, RunRequest = runRequest }, cancellationToken); // response.Status is Finished, Suspended, or Faulted Console.WriteLine($"Instance {client.WorkflowInstanceId} status: {response.Status}"); return client.WorkflowInstanceId; } public async Task CancelOrderWorkflowAsync(string instanceId, CancellationToken cancellationToken = default) { var client = await workflowRuntime.CreateClientAsync(instanceId, cancellationToken); await client.CancelAsync(cancellationToken); } } ``` -------------------------------- ### Execute Workflow with IWorkflowRunner Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/qa/test-guidelines.md Shows how to execute a workflow object or loaded definition using IWorkflowRunner. Useful for asserting logical flow and outputs. Requires service provider setup. ```csharp var runner = serviceProvider.GetRequiredService(); await serviceProvider.PopulateRegistriesAsync(); var runResult = await runner.RunAsync(workflow); Assert.Equal(WorkflowStatus.Finished, runResult.WorkflowInstance!.Status); ``` -------------------------------- ### Tenant-Agnostic Workflow JSON Example Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/adr/0009-asterisk-sentinel-value-for-tenant-agnostic-entities.md This JSON structure demonstrates how to define a tenant-agnostic workflow by explicitly setting the 'tenantId' field to '*'. This ensures the workflow is shared across all tenants. ```json { "tenantId": "*", "name": "GlobalApprovalWorkflow", "description": "Shared across all tenants", "root": { ... } } ``` -------------------------------- ### Register Elsa Services with AddElsa Source: https://context7.com/elsa-workflows/elsa-core/llms.txt Use `AddElsa` in `Program.cs` to register Elsa services and configure features like identity, workflows, persistence, APIs, and scripting. This example demonstrates configuring Elsa with identity, EF Core for SQLite persistence, REST API, and various scripting and activity modules. ```csharp // Program.cs var builder = WebApplication.CreateBuilder(args); builder.Services.AddElsa(elsa => { elsa // Scan the current assembly for WorkflowBase / Activity subclasses .AddWorkflowsFrom() .AddActivitiesFrom() // Identity & JWT auth .UseIdentity(identity => { identity.UseConfigurationBasedUserProvider(opts => builder.Configuration.GetSection("Identity").Bind(opts)); identity.UseConfigurationBasedApplicationProvider(opts => builder.Configuration.GetSection("Identity").Bind(opts)); identity.UseConfigurationBasedRoleProvider(opts => builder.Configuration.GetSection("Identity").Bind(opts)); }) .UseDefaultAuthentication() // Workflow engine .UseWorkflows() .UseFlowchart() // Persistence with EF Core + SQLite .UseWorkflowManagement(m => m.UseEntityFrameworkCore(ef => ef.UseSqlite())) .UseWorkflowRuntime(r => r.UseEntityFrameworkCore(ef => ef.UseSqlite())) // REST API for Elsa Studio .UseWorkflowsApi() // Scripting .UseCSharp() .UseJavaScript() .UseLiquid() // HTTP activities .UseHttp() // Scheduling activities .UseScheduling()); var app = builder.Build(); app.UseCors(); app.UseAuthentication(); app.UseAuthorization(); app.UseWorkflowsApi(); // Mount Elsa API routes app.UseWorkflows(); // Mount HttpEndpoint activity routes await app.RunAsync(); ``` -------------------------------- ### Test JavaScript Expression Evaluation with Dynamic Accessors Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/qa/test-guidelines.md This example demonstrates testing JavaScript expression evaluation using dynamic variable accessors within an expression execution context. It shows how to set and retrieve variables from JavaScript. ```csharp [Fact] public async Task Dynamic_Variable_Accessors_Should_Work() { // Arrange var script = @" setMyVariable('updated value'); return getMyVariable(); "; var context = await _fixture.CreateExpressionExecutionContextAsync(new[] { new Variable("MyVariable", "initial value") }); // Act var evaluator = _fixture.Services.GetRequiredService(); var result = await evaluator.EvaluateAsync(script, typeof(string), context); // Assert Assert.Equal("updated value", result); } ``` -------------------------------- ### Resume a bookmark Source: https://context7.com/elsa-workflows/elsa-core/llms.txt Resumes a suspended workflow instance using a time-limited signed URL token. Supports synchronous resume via GET and asynchronous resume with input via POST. The SAS token is typically embedded in the URL. ```bash # The SAS token is embedded in the URL typically sent to an external party. # Token is obtained when the workflow issues a bookmark and the application generates the URL. SAS_TOKEN="" # Synchronous resume (GET) curl -s "http://localhost:13000/elsa/api/bookmarks/resume?t=$SAS_TOKEN" # Asynchronous resume with input (POST) curl -s -X POST "http://localhost:13000/elsa/api/bookmarks/resume?t=$SAS_TOKEN&async=true" \ -H "Content-Type: application/json" \ -d '{"input": {"Approved": true, "ApproverNotes": "Looks good"}}' ``` -------------------------------- ### Resume a bookmark via SAS token Source: https://context7.com/elsa-workflows/elsa-core/llms.txt Resumes a suspended workflow instance using a time-limited signed URL token. Useful for email-click confirmations or one-time callback URLs. Supports both GET and POST requests. ```APIDOC ## GET|POST /bookmarks/resume ### Description Resumes a suspended workflow instance using a time-limited signed URL token. Useful for email-click confirmations or one-time callback URLs. ### Method GET | POST ### Endpoint /bookmarks/resume ### Parameters #### Query Parameters - **t** (string) - Required - The signed SAS token. - **async** (boolean) - Optional - If true, the resume operation will be performed asynchronously. #### Request Body (for POST) - **input** (object) - Optional - Input values to provide to the workflow upon resuming. - **Approved** (boolean) - Example input field. - **ApproverNotes** (string) - Example input field. ### Request Example (Synchronous resume - GET) ```bash curl -s "http://localhost:13000/elsa/api/bookmarks/resume?t=$SAS_TOKEN" ``` ### Request Example (Asynchronous resume with input - POST) ```bash curl -s -X POST "http://localhost:13000/elsa/api/bookmarks/resume?t=$SAS_TOKEN&async=true" \ -H "Content-Type: application/json" \ -d '{"input": {"Approved": true, "ApproverNotes": "Looks good"}}' ``` ``` -------------------------------- ### Run Elsa Studio and Server with Docker Source: https://github.com/elsa-workflows/elsa-core/blob/main/README.md This command pulls the latest Elsa Docker image and runs it, exposing the Studio and Server on specified ports. It's intended for quick testing and not for production use. ```shell docker pull elsaworkflows/elsa-server-and-studio-v3:latest docker run -t -i -e ASPNETCORE_ENVIRONMENT='Development' -e HTTP_PORTS=8080 -e HTTP__BASEURL=http://localhost:13000 -p 13000:8080 elsaworkflows/elsa-server-and-studio-v3:latest ``` -------------------------------- ### Resume Workflow Bookmark (Component/Integration Test) Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/qa/test-guidelines.md Use this pattern to resume a workflow instance from a specific bookmark. Ensure the instanceId is correctly identified, typically from a previous run or correlation ID. The workflow is then executed using the runner, and its final status is asserted. ```csharp // assume instanceId found via RunAsync or correlation id await workflowTriggerService.ResumeAsync(instanceId, activityId, input, CancellationToken.None); var resumed = await runner.RunAsync(workflowInstance); Assert.Equal(WorkflowStatus.Finished, resumed.WorkflowInstance.Status); ``` -------------------------------- ### Integration Test with WorkflowTestFixture Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/qa/test-guidelines.md Use WorkflowTestFixture for standard activity integration tests. It simplifies setup and execution of individual activities. ```csharp public class MyActivityTests { private readonly WorkflowTestFixture _fixture; public MyActivityTests(ITestOutputHelper testOutputHelper) { _fixture = new WorkflowTestFixture(testOutputHelper); } [Fact] public async Task Activity_Completes_Successfully() { // Arrange var activity = new MyActivity { Input = new("test") }; // Act var result = await _fixture.RunActivityAsync(activity); // Assert Assert.Equal(WorkflowStatus.Finished, result.WorkflowState.Status); } } ``` -------------------------------- ### Cron Trigger Source: https://context7.com/elsa-workflows/elsa-core/llms.txt A trigger/activity that fires on a CRON schedule. When used as a trigger it starts a new workflow instance; when embedded mid-flow it suspends until the next occurrence. ```APIDOC ## Cron Trigger ### Description A trigger/activity that fires on a CRON schedule. When used as a trigger it starts a new workflow instance; when embedded mid-flow it suspends until the next occurrence. ### Usage ```csharp // Workflow that runs every weekday at 08:00 public class DailyReportWorkflow : WorkflowBase { protected override void Build(IWorkflowBuilder builder) { builder.Root = new Sequence { Activities = { new Cron("0 8 * * 1-5") // Mon–Fri at 08:00 { CanStartWorkflow = true }, new WriteLine("Generating daily report..."), new SendHttpRequest { Url = new("https://reports.internal/generate"), Method = new("POST") } } }; } } // Using the static factory: var timer = Cron.FromCronExpression("*/5 * * * *"); // Every 5 minutes ``` ### Parameters - **cronExpression** (string) - Required - The CRON expression defining the schedule. - **CanStartWorkflow** (boolean) - Optional - If true, this trigger can start a new workflow instance. ``` -------------------------------- ### Component Test for Persistence Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/qa/test-guidelines.md Component tests can verify workflow persistence and journal entries. This example uses AsyncWorkflowRunner to run a workflow and check its final status. ```csharp [Fact] public async Task Workflow_Persists_Instance_And_Journal() { var sp = new TestApplicationBuilder(testOutput) .Build(); var runner = sp.GetRequiredService(); var result = await runner.RunAndAwaitWorkflowCompletionAsync( WorkflowDefinitionHandle.ByDefinitionId(someDefinitionId, VersionOptions.Published) ); result.WorkflowExecutionContext.Status.Should().Be(WorkflowStatus.Finished); } ``` -------------------------------- ### Retrieving All Activity Outcomes with WorkflowTestFixture Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/qa/test-guidelines.md Get a collection of all outcomes produced by an activity using the `GetOutcomes` helper method. This is useful when an activity can produce multiple results. ```csharp var result = await _fixture.RunActivityAsync(activity); var outcomes = _fixture.GetOutcomes(result, activity); Assert.Contains("ExpectedOutcome", outcomes); ``` -------------------------------- ### Run HttpEndpoint Tests with Detailed Output Source: https://github.com/elsa-workflows/elsa-core/blob/main/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/README.md Execute all HttpEndpoint tests and display detailed output. This is useful for debugging and understanding the test execution flow. ```bash dotnet test --filter "FullyQualifiedName~HttpEndpoint" --verbosity detailed ``` -------------------------------- ### Create Activity Execution Context (With Workflow) Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/qa/test-guidelines.md Use `CreateActivityExecutionContextAsync` with an existing workflow context to create an activity execution context. This allows testing activities within a pre-defined workflow state. ```csharp var workflowContext = await _fixture.CreateWorkflowExecutionContextAsync(); var activityContext = await _fixture.CreateActivityExecutionContextAsync( workflowContext, activity: myActivity ); ``` -------------------------------- ### Unit Test Activity with HTTP Services and Output Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/qa/test-guidelines.md Configure HTTP services using WithHttpServices() for activities like SendHttpRequest. Assert activity outputs using context.GetActivityOutput(). ```csharp { // Arrange var expectedUrl = new Uri("https://example.com"); var sendHttpRequest = new SendHttpRequest { Url = new Input(expectedUrl), Method = new Input("GET") }; // Act var fixture = new ActivityTestFixture(sendHttpRequest) .WithHttpServices(responseHandler); // HTTP-specific extension var context = await fixture.ExecuteAsync(); // Assert var statusCodeOutput = context.GetActivityOutput(_ => sendHttpRequest.StatusCode); Assert.Equal(200, statusCodeOutput); } ``` -------------------------------- ### Integration Test with IWorkflowRunner Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/qa/test-guidelines.md Use IWorkflowRunner.RunAsync for integration tests when manual setup or more control over the workflow execution environment is needed. This approach requires building a test application and populating registries. ```csharp [Fact] public async Task Workflow_With_MyActivity_Completes() { var sp = new TestApplicationBuilder(testOutput).Build(); await sp.PopulateRegistriesAsync(); var runner = sp.GetRequiredService(); var workflow = new MyWorkflowDefinition(); var result = await runner.RunAsync(workflow); Assert.Equal(WorkflowStatus.Finished, result.WorkflowInstance!.Status); } ``` -------------------------------- ### Create a custom hash computation activity in C# Source: https://context7.com/elsa-workflows/elsa-core/llms.txt Create custom activities by inheriting from `CodeActivity` for automatic completion. Use `[Input]` attributes to define activity inputs and `context.Get()` to retrieve their values. The `Result` property is used to set the activity's output. ```csharp using Elsa.Workflows; using Elsa.Workflows.Attributes; using Elsa.Workflows.Models; [Activity("MyCompany", "Utilities", "Computes the hash of a string.")] public class ComputeHash : CodeActivity { [Input(Description = "The string to hash.")] public Input Value { get; set; } = new(string.Empty); [Input(Description = "The algorithm to use (MD5, SHA256).")] public Input Algorithm { get; set; } = new("SHA256"); protected override void Execute(ActivityExecutionContext context) { var value = context.Get(Value)!; var algo = context.Get(Algorithm)!; using var hash = algo.ToUpperInvariant() == "MD5" ? (System.Security.Cryptography.HashAlgorithm)System.Security.Cryptography.MD5.Create() : System.Security.Cryptography.SHA256.Create(); var bytes = hash.ComputeHash(System.Text.Encoding.UTF8.GetBytes(value)); var result = Convert.ToHexString(bytes).ToLowerInvariant(); context.Set(Result, result); // No CompleteActivityAsync needed — CodeActivity handles it automatically. } } ``` -------------------------------- ### Configure Default Admin User in C# Code Source: https://github.com/elsa-workflows/elsa-core/blob/main/src/modules/Elsa.Identity/README.md Configure the default admin user and role using the `UseDefaultAdmin` extension method within the `AddElsa` configuration. This approach is suitable for code-first setups. ```csharp services.AddElsa(elsa => { elsa .UseIdentity(identity => { identity.TokenOptions += options => { options.SigningKey = "CHANGE_ME_TO_A_SECURE_RANDOM_KEY"; }; identity.UseDefaultAdmin(admin => admin .WithAdminUserName("admin") .WithAdminPassword("password") .WithAdminRoleName("admin") .WithAdminRolePermissions(new List { "*" })); }) .UseDefaultAuthentication(); }); ``` ```csharp identity.UseDefaultAdmin("admin", "password", "admin", new List { "*" }); ``` -------------------------------- ### Configure Default Admin User in appsettings.json Source: https://github.com/elsa-workflows/elsa-core/blob/main/src/modules/Elsa.Identity/README.md Use this JSON configuration within `CShells` to set up the default admin user, password, role, and permissions. Ensure the `SigningKey` is kept secure. ```json { "CShells": { "Shells": [ { "Name": "Default", "Features": { "Identity": { "SigningKey": "CHANGE_ME_TO_A_SECURE_RANDOM_KEY" }, "DefaultAuthentication": {}, "DefaultAdminUser": { "AdminUserName": "admin", "AdminPassword": "password", "AdminRoleName": "admin", "AdminRolePermissions": ["*"] } } } ] } } ``` -------------------------------- ### Use a custom activity within a workflow in C# Source: https://context7.com/elsa-workflows/elsa-core/llms.txt Demonstrates how to integrate a custom activity (`ComputeHash`) into a workflow. Inputs are provided directly, and the output is mapped to a workflow variable using `Result`. ```csharp // Usage inside a workflow public class HashWorkflow : WorkflowBase { protected override void Build(IWorkflowBuilder builder) { var hashVar = new Variable("Hash"); builder.Variables.Add(hashVar); builder.Root = new Sequence { Activities = { new ComputeHash { Value = new("Hello, Elsa!"), Algorithm = new("SHA256"), Result = new(hashVar) }, new WriteLine(context => $"Hash: {hashVar.Get(context)}") } }; } } ``` -------------------------------- ### Tenant ID Flow and Handling Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/adr/0009-asterisk-sentinel-value-for-tenant-agnostic-entities.md Illustrates the lifecycle of a TenantId from entity creation through deserialization, application, database storage, EF Core querying, and in-memory registry lookup. Note that null is transient and converted to the default tenant, while '*' is permanent and preserved. ```text ┌─────────────────────────────────────────────────────────────┐ │ Entity Creation / Deserialization │ ├─────────────────────────────────────────────────────────────┤ │ TenantId = null → Not yet assigned │ │ TenantId = "*" → Explicitly agnostic │ │ TenantId = "" → Default tenant │ │ TenantId = "foo" → Specific tenant "foo" │ └─────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────┐ │ ApplyTenantId Handler (before DB save) │ ├─────────────────────────────────────────────────────────────┤ │ TenantId = "*" → PRESERVED (agnostic) │ │ TenantId = null → SET to current tenant from context │ │ TenantId = "" → PRESERVED (default tenant) │ │ TenantId = "foo" → PRESERVED (specific tenant) │ └─────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────┐ │ Database Storage │ ├─────────────────────────────────────────────────────────────┤ │ TenantId = "*" → Stored as "*" (agnostic) │ │ TenantId = "" → Stored as "" (default tenant) │ │ TenantId = "foo" → Stored as "foo" (specific tenant) │ │ NOTE: No null values in DB after ApplyTenantId handler │ └─────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────┐ │ SetTenantIdFilter (EF Core Query) │ ├─────────────────────────────────────────────────────────────┤ │ Returns: TenantId == current_tenant OR TenantId == "*" │ │ Result: Tenant-specific records + agnostic records │ └─────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────┐ │ ActivityRegistry (In-Memory) │ ├─────────────────────────────────────────────────────────────┤ │ null or "*" → _agnosticRegistry (shared) │ │ TenantId="" → _tenantRegistries[""] (default) │ │ TenantId=X → _tenantRegistries[X] (specific tenant X) │ └─────────────────────────────────────────────────────────────┘ ``` -------------------------------- ### Run All Integration Tests Source: https://github.com/elsa-workflows/elsa-core/blob/main/test/integration/Elsa.Http.IntegrationTests/README.md Execute all integration tests within the Elsa.Http.IntegrationTests project. ```bash dotnet test Elsa.Http.IntegrationTests.csproj ``` -------------------------------- ### Create Activity Execution Context (No Workflow) Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/qa/test-guidelines.md Use `CreateActivityExecutionContextAsync` without an existing workflow context to automatically create one. This is useful for testing activities in isolation with specific variables. ```csharp var activityContext = await _fixture.CreateActivityExecutionContextAsync( activity: myActivity, variables: new[] { new Variable("MyVar", "value") } ); ``` -------------------------------- ### Run All HttpEndpoint Tests Source: https://github.com/elsa-workflows/elsa-core/blob/main/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Http/README.md Execute all component tests related to the HttpEndpoint activity. Use this command to ensure comprehensive testing of the HttpEndpoint functionality. ```bash dotnet test --filter "FullyQualifiedName~HttpEndpoint" ``` -------------------------------- ### Execute Activities Sequentially with Sequence Source: https://context7.com/elsa-workflows/elsa-core/llms.txt The `Sequence` activity executes its child activities in order. It supports early exit using the `Break` activity. ```csharp using Elsa.Workflows.Activities; var workflow = new Sequence { Activities = { new WriteLine("Step 1: Validating order"), new If( condition: new Input(true), then: new WriteLine("Order is valid"), @else: new Fault { Message = new("Order validation failed") } ), new WriteLine("Step 2: Processing payment"), new Delay(TimeSpan.FromSeconds(5)), // Suspend for 5 seconds new WriteLine("Step 3: Sending confirmation email"), } }; ``` -------------------------------- ### List workflow instances Source: https://context7.com/elsa-workflows/elsa-core/llms.txt Queries running and completed workflow instances, supporting filtering by status, sub-status, definition, correlation ID, and timestamp ranges. Requires a bearer token. ```bash TOKEN="" # Running instances only curl -s "http://localhost:13000/elsa/api/workflow-instances?statuses=Running&page=1&pageSize=25" \ -H "Authorization: Bearer $TOKEN" | jq '{total: .totalCount, items: [.items[] | {id, name, status, subStatus, correlationId}]}' # Faulted instances for a specific workflow curl -s "http://localhost:13000/elsa/api/workflow-instances?definitionId=$DEF_ID&subStatuses=Faulted" \ -H "Authorization: Bearer $TOKEN" | jq . # Filter by correlation ID (POST form also accepted) curl -s -X POST http://localhost:13000/elsa/api/workflow-instances \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"correlationId": "order-12345"}' | jq . ``` -------------------------------- ### IWorkflowClient - Programmatic workflow instance management Source: https://context7.com/elsa-workflows/elsa-core/llms.txt The primary in-process API for creating and running workflow instances. Retrieve a client from `IWorkflowRuntime.CreateClientAsync()`. ```APIDOC ## `IWorkflowClient` Interface ### Description Provides programmatic control over workflow instances, including creation, execution, and cancellation. ### Methods #### `CreateAndRunInstanceAsync` Creates and immediately runs a new workflow instance. **Parameters:** - `CreateAndRunWorkflowInstanceRequest` (object) - Request object containing creation and run details. - `CreateRequest` (`CreateWorkflowInstanceRequest`) - Details for creating the workflow instance. - `WorkflowDefinitionHandle` (`WorkflowDefinitionHandle`) - Handle to the workflow definition (e.g., by ID). - `CorrelationId` (string) - Optional correlation ID for the instance. - `Input` (Dictionary) - Input variables for the workflow. - `RunRequest` (`RunWorkflowInstanceRequest`) - Optional request for running the instance. **Returns:** `RunWorkflowInstanceResponse` - Response indicating the status of the created and run instance. #### `CancelAsync` Cancels a running workflow instance. **Parameters:** - `CancellationToken` (CancellationToken) - Token for cancellation. #### `CreateClientAsync` (from `IWorkflowRuntime`) Retrieves an `IWorkflowClient` instance. **Parameters:** - `WorkflowDefinitionHandle` or `instanceId` (WorkflowDefinitionHandle or string) - Handle to the workflow definition or the ID of an existing instance. - `CancellationToken` (CancellationToken) - Token for cancellation. **Returns:** `Task` - A task that resolves to an `IWorkflowClient`. ``` -------------------------------- ### Clone Elsa Core Repository using Git Source: https://github.com/elsa-workflows/elsa-core/blob/main/README.md Clone the Elsa core repository from GitHub to your local machine. Replace 'YOUR_USERNAME' with your actual GitHub username. ```bash git clone https://github.com/YOUR_USERNAME/elsa-core.git ``` -------------------------------- ### Create Expression Execution Context (With Activity) Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/qa/test-guidelines.md Use `CreateExpressionExecutionContextAsync` with an existing activity context to create a context for expression evaluation. This allows testing expressions within the scope of an activity. ```csharp var activityContext = await _fixture.CreateActivityExecutionContextAsync(); var expressionContext = await _fixture.CreateExpressionExecutionContextAsync( activityContext, variables: new[] { new Variable("Count", 42) } ); ``` -------------------------------- ### Refactored Single Instance Delete Endpoint (C#) Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/agent-logs/7077/2025-11-20_workflow-instance-deletion_runtime-coordination.md Demonstrates the updated `Delete` endpoint using `IWorkflowRuntime` to create a client for coordinated deletion of a single workflow instance. ```csharp internal class Delete(IWorkflowRuntime workflowRuntime) : ElsaEndpoint { public override async Task HandleAsync(Request request, CancellationToken cancellationToken) { var client = await workflowRuntime.CreateClientAsync(request.Id, cancellationToken); var deleted = await client.DeleteAsync(cancellationToken); // ... } } ``` -------------------------------- ### Bulk publish workflow definitions Source: https://context7.com/elsa-workflows/elsa-core/llms.txt Publishes multiple workflow definitions at once. Requires a bearer token and a JSON payload containing definition IDs. ```bash TOKEN="" DEF_ID="" curl -s -X POST http://localhost:13000/elsa/api/bulk-actions/publish/workflow-definitions \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d "{\"definitionIds\": [\"$DEF_ID\"]}" | jq . ``` -------------------------------- ### Schedule Workflow with Cron Source: https://context7.com/elsa-workflows/elsa-core/llms.txt Defines a workflow that executes on a recurring CRON schedule. Use `Cron.FromCronExpression` for static factory creation. ```csharp using Elsa.Scheduling.Activities; using Elsa.Workflows; using Elsa.Workflows.Activities; // Workflow that runs every weekday at 08:00 public class DailyReportWorkflow : WorkflowBase { protected override void Build(IWorkflowBuilder builder) { builder.Root = new Sequence { Activities = { new Cron("0 8 * * 1-5") // Mon–Fri at 08:00 { CanStartWorkflow = true }, new WriteLine("Generating daily report..."), new SendHttpRequest { Url = new("https://reports.internal/generate"), Method = new("POST") } } }; } } // Using the static factory: var timer = Cron.FromCronExpression("*/5 * * * *"); // Every 5 minutes ``` -------------------------------- ### Create Workflow Execution Context Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/qa/test-guidelines.md Use `CreateWorkflowExecutionContextAsync` to create a minimal workflow execution context for testing without running the workflow. Useful for setting up initial variables. ```csharp var context = await _fixture.CreateWorkflowExecutionContextAsync(variables: new[] { new Variable("Counter", 0) }); ``` -------------------------------- ### Bulk Delete Endpoint - Phase 1: Delete Running Instances (C#) Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/agent-logs/7077/2025-11-20_workflow-instance-deletion_runtime-coordination.md Handles the first phase of bulk deletion by individually deleting running workflow instances using the `IWorkflowRuntime` for coordination. ```csharp // Step 1: Delete running instances individually (requires coordination by the workflow runtime). var runningFilter = new WorkflowInstanceFilter { Ids = baseFilter.Ids, DefinitionId = baseFilter.DefinitionId, DefinitionIds = baseFilter.DefinitionIds, WorkflowStatus = WorkflowStatus.Running }; var runningInstanceIds = await workflowInstanceStore.FindManyIdsAsync(runningFilter, cancellationToken); var count = 0L; foreach (var instanceId in runningInstanceIds) { var client = await workflowRuntime.CreateClientAsync(instanceId, cancellationToken); var deleted = await client.DeleteAsync(cancellationToken); if (deleted) count++; } ``` -------------------------------- ### Register Resolver Strategy with Factory in C# Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/agent-logs/cshells-changes-summary.md Supports registering resolver strategies using a factory function, allowing for explicit instantiation control during pipeline building. This is useful when DI constructor selection is not desired or needs to be overridden. ```csharp Use(Func factory, int? order = null) ``` -------------------------------- ### Integration Test with WorkflowTestFixture Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/qa/test-guidelines.md Demonstrates integration testing of a RunJavaScript activity using WorkflowTestFixture. Covers asserting activity output, outcomes, and fault states. ```csharp public class RunJavaScriptTests { private readonly WorkflowTestFixture _fixture; public RunJavaScriptTests(ITestOutputHelper testOutputHelper) { _fixture = new WorkflowTestFixture(testOutputHelper); } [Fact(DisplayName = "RunJavaScript should execute and return output")] public async Task Should_Execute_And_Return_Output() { // Arrange var script = "return 1 + 1;"; var activity = new RunJavaScript { Script = new(script), Result = new() }; // Act var result = await _fixture.RunActivityAsync(activity); // Assert - activity produced expected output var output = result.GetActivityOutput(activity); Assert.Equal(2, output); } [Fact(DisplayName = "RunJavaScript should set outcomes")] public async Task Should_Set_Outcomes() { // Arrange var script = "setOutcomes(['Branch1', 'Branch2']);"; var activity = new RunJavaScript { Script = new(script) }; // Act var result = await _fixture.RunActivityAsync(activity); // Assert - activity produced expected outcomes var outcomes = _fixture.GetOutcomes(result, activity); Assert.Contains("Branch1", outcomes); Assert.Contains("Branch2", outcomes); } [Fact(DisplayName = "RunJavaScript should fault on invalid syntax")] public async Task Should_Fault_On_Invalid_Syntax() { // Arrange var script = "this is not valid javascript"; var activity = new RunJavaScript { Script = new(script) }; // Act var result = await _fixture.RunActivityAsync(activity); // Assert - activity should be in faulted state var status = _fixture.GetActivityStatus(result, activity); Assert.Equal(ActivityStatus.Faulted, status); } } ``` -------------------------------- ### Create Expression Execution Context (No Activity) Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/qa/test-guidelines.md Use `CreateExpressionExecutionContextAsync` without an existing activity context to create a context for testing expression evaluation. Variables are automatically registered and accessible via dynamic accessors. ```csharp var expressionContext = await _fixture.CreateExpressionExecutionContextAsync(new[] { new Variable("MyVariable", "test value") }); // Variables are accessible via dynamic accessors in expressions // e.g., getMyVariable() and setMyVariable(value) in JavaScript ``` -------------------------------- ### Asserting Activity Output with ActivityTestFixture Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/qa/test-guidelines.md Retrieve and assert on the output value of an activity using the `GetActivityOutput` method. Ensure the expected value matches the actual output. ```csharp var result = await _fixture.RunActivityAsync(activity); var output = result.GetActivityOutput(activity); Assert.Equal(expectedValue, output); ``` -------------------------------- ### WriteHttpResponse Faults on HTTP Context Loss Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/agent-logs/http-context-loss-error-messaging.md This code demonstrates how WriteHttpResponse now immediately faults with a detailed exception when the HTTP context is unavailable, instead of creating a bookmark. ```csharp public override async ValueTask ExecuteAsync(ActivityExecutionContext context) { var httpContext = _httpContextAccessor.HttpContext; if (httpContext == null) { // Previously, a bookmark would be created here to allow resumption in a different context. // Now, the activity faults immediately. throw new FaultException(new Fault(HttpFaultCodes.NoHttpContext, "The HTTP context was lost during workflow execution. This can happen if a workflow initiated from an HTTP endpoint is suspended and later resumed in a different execution context (e.g. background processing, virtual actor, or after a workflow transition). The original HTTP request context that expects a response is no longer available.")); } // ... existing logic to write HTTP response ... } ``` -------------------------------- ### Bulk Delete Endpoint - Phase 2: Bulk Delete Finished Instances (C#) Source: https://github.com/elsa-workflows/elsa-core/blob/main/doc/agent-logs/7077/2025-11-20_workflow-instance-deletion_runtime-coordination.md Handles the second phase of bulk deletion by efficiently deleting finished workflow instances using `IWorkflowInstanceManager`. ```csharp // Step 2: Bulk delete finished instances (no coordination needed). // Use IWorkflowInstanceManager to ensure related records are also deleted. var finishedFilter = new WorkflowInstanceFilter { Ids = baseFilter.Ids, DefinitionId = baseFilter.DefinitionId, DefinitionIds = baseFilter.DefinitionIds, WorkflowStatus = WorkflowStatus.Finished }; var finishedDeletedCount = await workflowInstanceManager.BulkDeleteAsync(finishedFilter, cancellationToken); count += finishedDeletedCount; ```