Fix naming collision between workflow input and activity input
This commit is contained in:
parent
6eda27b034
commit
69744bd63c
|
|
@ -53,10 +53,11 @@ public static class ServiceProviderExtensions
|
|||
/// </summary>
|
||||
/// <param name="services">The services.</param>
|
||||
/// <param name="workflowDefinitionId">The ID of the workflow definition.</param>
|
||||
/// <param name="input">An optional dictionary of input values.</param>
|
||||
/// <returns>The workflow state.</returns>
|
||||
public static async Task<WorkflowState> RunWorkflowUntilEndAsync(this IServiceProvider services, string workflowDefinitionId)
|
||||
public static async Task<WorkflowState> RunWorkflowUntilEndAsync(this IServiceProvider services, string workflowDefinitionId, IDictionary<string, object>? input = default)
|
||||
{
|
||||
var startWorkflowOptions = new StartWorkflowRuntimeOptions(null, new Dictionary<string, object>(), VersionOptions.Published);
|
||||
var startWorkflowOptions = new StartWorkflowRuntimeOptions(null, input, VersionOptions.Published);
|
||||
var workflowRuntime = services.GetRequiredService<IWorkflowRuntime>();
|
||||
var result = await workflowRuntime.StartWorkflowAsync(workflowDefinitionId, startWorkflowOptions);
|
||||
var bookmarks = new Stack<Bookmark>(result.Bookmarks);
|
||||
|
|
@ -67,7 +68,7 @@ public static class ServiceProviderExtensions
|
|||
var resumeOptions = new ResumeWorkflowRuntimeOptions(BookmarkId: bookmark.Id);
|
||||
var resumeResult = await workflowRuntime.ResumeWorkflowAsync(result.WorkflowInstanceId, resumeOptions);
|
||||
|
||||
foreach (var newBookmark in resumeResult.Bookmarks)
|
||||
foreach (var newBookmark in resumeResult!.Bookmarks)
|
||||
bookmarks.Push(newBookmark);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using Elsa.JavaScript.Extensions;
|
|||
using Elsa.JavaScript.Notifications;
|
||||
using Elsa.JavaScript.Options;
|
||||
using Elsa.Mediator.Contracts;
|
||||
using Elsa.Workflows.Core.Activities;
|
||||
using Elsa.Workflows.Core.Memory;
|
||||
using Humanizer;
|
||||
using Jint;
|
||||
|
|
@ -67,12 +68,14 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
|
|||
engine.SetValue("getInput", (Func<string, object?>)(name => context.GetWorkflowExecutionContext().Input.GetValue(name)));
|
||||
engine.SetValue("getOutputFrom", (Func<string, string?, object?>)((activityIdOrNodeId, outputName) => GetOutput(context, activityIdOrNodeId, outputName)));
|
||||
engine.SetValue("getLastResult", (Func<object?>)(() => GetLastResult(context)));
|
||||
|
||||
// Create workflow input accessors.
|
||||
CreateWorkflowInputAccessors(engine, context);
|
||||
|
||||
// Create variable getters and setters for each variable.
|
||||
CreateVariableAccessors(engine, context);
|
||||
|
||||
// Create workflow input accessors - only if the current activity is not part of a composite activity definition.
|
||||
// Otherwise, the workflow input accessors will hide the composite activity input accessors which rely on variable accessors created above.
|
||||
if(!IsInsideCompositeActivity(context))
|
||||
CreateWorkflowInputAccessors(engine, context);
|
||||
|
||||
// Create output getters for each activity.
|
||||
CreateOutputAccessors(engine, context);
|
||||
|
|
@ -103,6 +106,17 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
|
|||
return engine;
|
||||
}
|
||||
|
||||
private static bool IsInsideCompositeActivity(ExpressionExecutionContext context)
|
||||
{
|
||||
if(!context.TryGetActivityExecutionContext(out var activityExecutionContext))
|
||||
return false;
|
||||
|
||||
// If the first workflow definition in the ancestor hierarchy and that workflow definition has a parent, then we are inside a composite activity.
|
||||
var firstWorkflowContext = activityExecutionContext.GetAncestors().FirstOrDefault(x => x.Activity is Workflow);
|
||||
|
||||
return firstWorkflowContext?.ParentActivityExecutionContext != null;
|
||||
}
|
||||
|
||||
private static object? GetLastResult(ExpressionExecutionContext context)
|
||||
{
|
||||
var workflowExecutionContext = context.GetWorkflowExecutionContext();
|
||||
|
|
@ -123,6 +137,11 @@ public class JintJavaScriptEvaluator : IJavaScriptEvaluator
|
|||
|
||||
private void CreateWorkflowInputAccessors(Engine engine, ExpressionExecutionContext context)
|
||||
{
|
||||
if(!context.TryGetActivityExecutionContext(out var activityExecutionContext))
|
||||
return;
|
||||
|
||||
// Only create workflow input accessors if the current activity is not part of a composite activity definition.
|
||||
|
||||
if(context.TryGetWorkflowExecutionContext(out var workflowExecutionContext))
|
||||
{
|
||||
var input = workflowExecutionContext.Input;
|
||||
|
|
|
|||
|
|
@ -87,8 +87,18 @@
|
|||
<None Update="Scenarios\FlowchartCompletion\Workflows\workflow5.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Scenarios\ParentChildInputs\Workflows\child.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Scenarios\ParentChildInputs\Workflows\parent1.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Scenarios\ParentChildInputs\Workflows\parent2.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Testing.Shared;
|
||||
using Elsa.Workflows.Core;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Elsa.IntegrationTests.Scenarios.ParentChildInputs;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for the flowchart completion feature using various workflow setups.
|
||||
/// </summary>
|
||||
public class Tests
|
||||
{
|
||||
private readonly CapturingTextWriter _capturingTextWriter = new();
|
||||
private readonly IServiceProvider _services;
|
||||
|
||||
public Tests(ITestOutputHelper testOutputHelper)
|
||||
{
|
||||
_services = new TestApplicationBuilder(testOutputHelper).WithCapturingTextWriter(_capturingTextWriter).Build();
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "Child activity receives workflow input from parent event if same name.")]
|
||||
public async Task Test1()
|
||||
{
|
||||
// Populate registries.
|
||||
await _services.PopulateRegistriesAsync();
|
||||
|
||||
// Import child workflow.
|
||||
var childFileName = $"Scenarios/ParentChildInputs/Workflows/child.json";
|
||||
await _services.ImportWorkflowDefinitionAsync(childFileName);
|
||||
|
||||
// Import parent workflow.
|
||||
var parentFileName = $"Scenarios/ParentChildInputs/Workflows/parent1.json";
|
||||
var workflowDefinition = await _services.ImportWorkflowDefinitionAsync(parentFileName);
|
||||
|
||||
// Execute.
|
||||
var input = new Dictionary<string, object> { ["Input1"] = "Foo" };
|
||||
await _services.RunWorkflowUntilEndAsync(workflowDefinition.DefinitionId, input);
|
||||
|
||||
// Assert expected output.
|
||||
var lines = _capturingTextWriter.Lines.ToList();
|
||||
Assert.Equal(new[] { "Parent: Foo", "Child: Bar" }, lines);
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "Child activity receives input from parent event if same name and does not use global workflow input.")]
|
||||
public async Task Test2()
|
||||
{
|
||||
// Populate registries.
|
||||
await _services.PopulateRegistriesAsync();
|
||||
|
||||
// Import child workflow.
|
||||
var childFileName = $"Scenarios/ParentChildInputs/Workflows/child.json";
|
||||
await _services.ImportWorkflowDefinitionAsync(childFileName);
|
||||
|
||||
// Import parent workflow.
|
||||
var parentFileName = $"Scenarios/ParentChildInputs/Workflows/parent2.json";
|
||||
var workflowDefinition = await _services.ImportWorkflowDefinitionAsync(parentFileName);
|
||||
|
||||
// Execute.
|
||||
var input = new Dictionary<string, object> { ["Input1"] = "Foo" };
|
||||
await _services.RunWorkflowUntilEndAsync(workflowDefinition.DefinitionId, input);
|
||||
|
||||
// Assert expected output.
|
||||
var lines = _capturingTextWriter.Lines.ToList();
|
||||
Assert.Equal(new[] { "Parent: Foo", "Child: Foo" }, lines);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
{
|
||||
"id": "228c0150ab7b4745b038b950be574935",
|
||||
"definitionId": "25b097966de245818e9a5c0d04f3323e",
|
||||
"name": "Child",
|
||||
"createdAt": "2023-09-06T09:57:32.944622+00:00",
|
||||
"version": 5,
|
||||
"variables": [],
|
||||
"inputs": [
|
||||
{
|
||||
"uiHint": "single-line",
|
||||
"storageDriverType": "Elsa.Workflows.Core.Services.WorkflowStorageDriver, Elsa.Workflows.Core",
|
||||
"type": "Object",
|
||||
"name": "Input1",
|
||||
"displayName": "Input1",
|
||||
"description": "",
|
||||
"category": "",
|
||||
"isArray": false
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"type": "Object",
|
||||
"name": "Output1",
|
||||
"displayName": "Output1",
|
||||
"description": "",
|
||||
"isArray": false
|
||||
}
|
||||
],
|
||||
"outcomes": [],
|
||||
"customProperties": {},
|
||||
"isReadonly": false,
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"options": {
|
||||
"usableAsActivity": true,
|
||||
"autoUpdateConsumingWorkflows": true
|
||||
},
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "Flowchart1",
|
||||
"metadata": {},
|
||||
"customProperties": {
|
||||
"source": "FlowchartJsonConverter.cs:45",
|
||||
"NotFoundConnectionsKey": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"start": "WriteLine1",
|
||||
"activities": [
|
||||
{
|
||||
"outputName": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": "Output1"
|
||||
},
|
||||
"memoryReference": {
|
||||
"id": "ca8473b5-83ec-4f75-a2f1-dfba71f349d1"
|
||||
}
|
||||
},
|
||||
"outputValue": {
|
||||
"typeName": "Object",
|
||||
"expression": {
|
||||
"type": "JavaScript",
|
||||
"value": "return getInput1();"
|
||||
},
|
||||
"memoryReference": {
|
||||
"id": "06c6243d-8a57-45e3-ae54-f209b95d2bb2"
|
||||
}
|
||||
},
|
||||
"id": "SetOutput1",
|
||||
"name": null,
|
||||
"type": "Elsa.SetOutput",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": 636,
|
||||
"y": 250.01388549804688
|
||||
},
|
||||
"size": {
|
||||
"width": 107.734375,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "JavaScript",
|
||||
"value": "\u0022Child: \u0022 \u002B getInput1();"
|
||||
},
|
||||
"memoryReference": {
|
||||
"id": "3f726554-0fa1-4e54-b5e7-74b18807437b"
|
||||
}
|
||||
},
|
||||
"id": "WriteLine1",
|
||||
"name": null,
|
||||
"type": "Elsa.WriteLine",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": 332.01385498046875,
|
||||
"y": 222.01388549804688
|
||||
},
|
||||
"size": {
|
||||
"width": 139.296875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"source": {
|
||||
"activity": "WriteLine1",
|
||||
"port": "Done"
|
||||
},
|
||||
"target": {
|
||||
"activity": "SetOutput1",
|
||||
"port": "In"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
{
|
||||
"id": "e49f81715e29460187671ee298bbd0b2",
|
||||
"definitionId": "6a4f5aeecbf94fc09dbba65363c5cb57",
|
||||
"name": "Parent1",
|
||||
"createdAt": "2023-09-06T11:38:10.701838+00:00",
|
||||
"version": 8,
|
||||
"variables": [],
|
||||
"inputs": [
|
||||
{
|
||||
"uiHint": "single-line",
|
||||
"storageDriverType": "Elsa.Workflows.Core.Services.WorkflowStorageDriver, Elsa.Workflows.Core",
|
||||
"type": "Object",
|
||||
"name": "Input1",
|
||||
"displayName": "Input1",
|
||||
"description": "",
|
||||
"category": "",
|
||||
"isArray": false
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"type": "Object",
|
||||
"name": "Output1",
|
||||
"displayName": "Output1",
|
||||
"description": "",
|
||||
"isArray": false
|
||||
}
|
||||
],
|
||||
"outcomes": [],
|
||||
"customProperties": {},
|
||||
"isReadonly": false,
|
||||
"isLatest": true,
|
||||
"isPublished": false,
|
||||
"options": {
|
||||
"autoUpdateConsumingWorkflows": false
|
||||
},
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "Flowchart1",
|
||||
"metadata": {},
|
||||
"customProperties": {
|
||||
"source": "FlowchartJsonConverter.cs:45",
|
||||
"NotFoundConnectionsKey": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"start": "WriteLine1",
|
||||
"activities": [
|
||||
{
|
||||
"text": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "JavaScript",
|
||||
"value": "\u0022Parent: \u0022 \u002B getInput1();"
|
||||
},
|
||||
"memoryReference": {
|
||||
"id": "3070bee4-8309-44e3-a805-a9ec7fdd7ac2"
|
||||
}
|
||||
},
|
||||
"id": "WriteLine1",
|
||||
"name": null,
|
||||
"type": "Elsa.WriteLine",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": 160,
|
||||
"y": 280
|
||||
},
|
||||
"size": {
|
||||
"width": 139.296875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"workflowDefinitionId": "25b097966de245818e9a5c0d04f3323e",
|
||||
"workflowDefinitionVersionId": "228c0150ab7b4745b038b950be574935",
|
||||
"latestAvailablePublishedVersion": 5,
|
||||
"latestAvailablePublishedVersionId": "228c0150ab7b4745b038b950be574935",
|
||||
"id": "22jW7xiYM0K30H99EDWztQ",
|
||||
"name": "Child1",
|
||||
"type": "Child",
|
||||
"version": 5,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": 405.3984375,
|
||||
"y": 204.0078125
|
||||
},
|
||||
"size": {
|
||||
"width": 94.765625,
|
||||
"height": 116.015625
|
||||
}
|
||||
}
|
||||
},
|
||||
"input1": {
|
||||
"typeName": "Object",
|
||||
"expression": {
|
||||
"type": "JavaScript",
|
||||
"value": "\u0060Bar\u0060"
|
||||
},
|
||||
"memoryReference": {
|
||||
"id": "22jW7xiYM0K30H99EDWztQ:input-0"
|
||||
}
|
||||
},
|
||||
"output1": {
|
||||
"typeName": "Object",
|
||||
"memoryReference": {
|
||||
"id": "Output1"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"source": {
|
||||
"activity": "WriteLine1",
|
||||
"port": "Done"
|
||||
},
|
||||
"target": {
|
||||
"activity": "22jW7xiYM0K30H99EDWztQ",
|
||||
"port": "In"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
{
|
||||
"id": "c5aa339e124f4486b14dbfdc133a45d1",
|
||||
"definitionId": "8ad20b5ff9ee4ff59b8dfcfb6d4e29a0",
|
||||
"name": "Parent2",
|
||||
"createdAt": "2023-09-06T11:38:30.217265+00:00",
|
||||
"version": 1,
|
||||
"variables": [],
|
||||
"inputs": [
|
||||
{
|
||||
"uiHint": "single-line",
|
||||
"storageDriverType": "Elsa.Workflows.Core.Services.WorkflowStorageDriver, Elsa.Workflows.Core",
|
||||
"type": "Object",
|
||||
"name": "Input1",
|
||||
"displayName": "Input1",
|
||||
"description": "",
|
||||
"category": "",
|
||||
"isArray": false
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"type": "Object",
|
||||
"name": "Output1",
|
||||
"displayName": "Output1",
|
||||
"description": "",
|
||||
"isArray": false
|
||||
}
|
||||
],
|
||||
"outcomes": [],
|
||||
"customProperties": {},
|
||||
"isReadonly": false,
|
||||
"isLatest": true,
|
||||
"isPublished": true,
|
||||
"options": {
|
||||
"autoUpdateConsumingWorkflows": false
|
||||
},
|
||||
"root": {
|
||||
"type": "Elsa.Flowchart",
|
||||
"version": 1,
|
||||
"id": "Flowchart1",
|
||||
"metadata": {},
|
||||
"customProperties": {
|
||||
"source": "FlowchartJsonConverter.cs:45",
|
||||
"NotFoundConnectionsKey": [],
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"start": "WriteLine1",
|
||||
"activities": [
|
||||
{
|
||||
"text": {
|
||||
"typeName": "String",
|
||||
"expression": {
|
||||
"type": "JavaScript",
|
||||
"value": "\u0022Parent: \u0022 \u002B getInput1();"
|
||||
},
|
||||
"memoryReference": {
|
||||
"id": "3070bee4-8309-44e3-a805-a9ec7fdd7ac2"
|
||||
}
|
||||
},
|
||||
"id": "WriteLine1",
|
||||
"name": null,
|
||||
"type": "Elsa.WriteLine",
|
||||
"version": 1,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": 160,
|
||||
"y": 280
|
||||
},
|
||||
"size": {
|
||||
"width": 139.296875,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"workflowDefinitionId": "25b097966de245818e9a5c0d04f3323e",
|
||||
"workflowDefinitionVersionId": "228c0150ab7b4745b038b950be574935",
|
||||
"latestAvailablePublishedVersion": 5,
|
||||
"latestAvailablePublishedVersionId": "228c0150ab7b4745b038b950be574935",
|
||||
"id": "22jW7xiYM0K30H99EDWztQ",
|
||||
"name": "Child1",
|
||||
"type": "Child",
|
||||
"version": 5,
|
||||
"customProperties": {
|
||||
"canStartWorkflow": false,
|
||||
"runAsynchronously": false
|
||||
},
|
||||
"metadata": {
|
||||
"designer": {
|
||||
"position": {
|
||||
"x": 405.3984375,
|
||||
"y": 204.0078125
|
||||
},
|
||||
"size": {
|
||||
"width": 135.390625,
|
||||
"height": 120
|
||||
}
|
||||
}
|
||||
},
|
||||
"input1": {
|
||||
"typeName": "Object",
|
||||
"expression": {
|
||||
"type": "JavaScript",
|
||||
"value": "getInput1()"
|
||||
},
|
||||
"memoryReference": {
|
||||
"id": "22jW7xiYM0K30H99EDWztQ:input-0"
|
||||
}
|
||||
},
|
||||
"output1": {
|
||||
"typeName": "Object",
|
||||
"memoryReference": {
|
||||
"id": "Output1"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"source": {
|
||||
"activity": "WriteLine1",
|
||||
"port": "Done"
|
||||
},
|
||||
"target": {
|
||||
"activity": "22jW7xiYM0K30H99EDWztQ",
|
||||
"port": "In"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue