diff --git a/src/modules/Elsa.Workflows.Core/Contexts/ActivityExecutionContext.Complete.cs b/src/modules/Elsa.Workflows.Core/Contexts/ActivityExecutionContext.Complete.cs index f3963ed91..28aa711ae 100644 --- a/src/modules/Elsa.Workflows.Core/Contexts/ActivityExecutionContext.Complete.cs +++ b/src/modules/Elsa.Workflows.Core/Contexts/ActivityExecutionContext.Complete.cs @@ -1,4 +1,3 @@ -using System.Diagnostics.CodeAnalysis; using Elsa.Extensions; using Elsa.Workflows.Activities.Flowchart.Models; using Elsa.Workflows.Contracts; @@ -11,7 +10,6 @@ public partial class ActivityExecutionContext /// /// Complete the current activity. This should only be called by activities that explicitly suppress automatic-completion. /// - [RequiresUnreferencedCode("The activity may be serialized and executed in a different context.")] public async ValueTask CompleteActivityAsync(object? result = default) { var outcomes = result as Outcomes; @@ -93,7 +91,6 @@ public partial class ActivityExecutionContext /// /// Complete the current activity with the specified outcomes. /// - [RequiresUnreferencedCode("The activity may be serialized and executed in a different context.")] public ValueTask CompleteActivityWithOutcomesAsync(params string[] outcomes) { return CompleteActivityAsync(new Outcomes(outcomes)); diff --git a/src/modules/Elsa.Workflows.Core/Contexts/ActivityExecutionContext.cs b/src/modules/Elsa.Workflows.Core/Contexts/ActivityExecutionContext.cs index 2be9c0b3d..d33473646 100644 --- a/src/modules/Elsa.Workflows.Core/Contexts/ActivityExecutionContext.cs +++ b/src/modules/Elsa.Workflows.Core/Contexts/ActivityExecutionContext.cs @@ -10,12 +10,14 @@ using Elsa.Workflows.Memory; using Elsa.Workflows.Models; using Elsa.Workflows.Options; using Elsa.Workflows.Services; +using JetBrains.Annotations; namespace Elsa.Workflows; /// /// Represents the context of an activity execution. /// +[PublicAPI] public partial class ActivityExecutionContext : IExecutionContext { private readonly ISystemClock _systemClock; diff --git a/src/modules/Elsa.Workflows.Core/Extensions/DictionaryExtensions.cs b/src/modules/Elsa.Workflows.Core/Extensions/DictionaryExtensions.cs index 3698b239c..c95267384 100644 --- a/src/modules/Elsa.Workflows.Core/Extensions/DictionaryExtensions.cs +++ b/src/modules/Elsa.Workflows.Core/Extensions/DictionaryExtensions.cs @@ -65,6 +65,16 @@ public static class DictionaryExtensions dictionary.Add(key, value); return dictionary; } + + /// + /// Merges the specified dictionary with the other dictionary. + /// When a key exists in both dictionaries, the value in the other dictionary will overwrite the value in the specified dictionary. + /// + public static void Merge(this IDictionary dictionary, IDictionary other) + { + foreach (var (key, value) in other) + dictionary[key] = value; + } private static T? ConvertValue(object? value) => value.ConvertTo(); } \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Runtime/Activities/BulkDispatchWorkflows.cs b/src/modules/Elsa.Workflows.Runtime/Activities/BulkDispatchWorkflows.cs index eade3320c..569f53647 100644 --- a/src/modules/Elsa.Workflows.Runtime/Activities/BulkDispatchWorkflows.cs +++ b/src/modules/Elsa.Workflows.Runtime/Activities/BulkDispatchWorkflows.cs @@ -55,19 +55,25 @@ public class BulkDispatchWorkflows : Activity [Input(Description = "The data source to use for dispatching the workflows.")] public Input Items { get; set; } = default!; + /// + /// The default key to use for the item input. Will not be used if the Items contain a list of dictionaries. + /// + [Input(Description = "The default key to use for the input name when sending the current item to the dispatched workflow. Will not be used if the Items field contain a list of dictionaries", DefaultValue = "Item")] + public Input DefaultItemInputKey { get; set; } = new("Item"); + /// /// The correlation ID to associate the workflow with. /// [Input( DisplayName = "Correlation ID Function", - Description = "A function to compute the correlation ID to associate a dispatched workflow with. Receives the current item as an argument called Item.", + Description = "A function to compute the correlation ID to associate a dispatched workflow with.", AutoEvaluate = false)] public Input? CorrelationIdFunction { get; set; } /// /// The input to send to the workflows. /// - [Input(Description = """Additional input to send to the workflows being dispatched. The "Item" key is reserved and should not be used.""")] + [Input(Description = "Additional input to send to the workflows being dispatched.")] public Input?> Input { get; set; } = default!; /// @@ -102,7 +108,6 @@ public class BulkDispatchWorkflows : Activity public IActivity? ChildFaulted { get; set; } /// - [RequiresUnreferencedCode("Calls Elsa.Expressions.Helpers.ObjectConverter.ConvertTo(ObjectConverterOptions)")] protected override async ValueTask ExecuteAsync(ActivityExecutionContext context) { var waitForCompletion = WaitForCompletion.GetOrDefault(context); @@ -162,20 +167,24 @@ public class BulkDispatchWorkflows : Activity var parentInstanceId = context.WorkflowExecutionContext.Id; var input = Input.GetOrDefault(context) ?? new Dictionary(); var channelName = ChannelName.GetOrDefault(context); + var defaultInputItemKey = DefaultItemInputKey.GetOrDefault(context, () => "Item")!; var properties = new Dictionary { ["ParentInstanceId"] = parentInstanceId }; + + var itemAsInputDictionary = item as IDictionary ?? new Dictionary + { + [defaultInputItemKey] = item + }; + var evaluatorOptions = new ExpressionEvaluatorOptions { - Arguments = new Dictionary - { - ["Item"] = item - } + Arguments = itemAsInputDictionary }; input["ParentInstanceId"] = parentInstanceId; - input["Item"] = item; + input.Merge(itemAsInputDictionary); var workflowDispatcher = context.GetRequiredService(); var identityGenerator = context.GetRequiredService(); @@ -198,7 +207,7 @@ public class BulkDispatchWorkflows : Activity }; var dispatchResponse = await workflowDispatcher.DispatchAsync(request, options, context.CancellationToken); - + if (!dispatchResponse.Succeeded) throw new FaultException(dispatchResponse.ErrorMessage);