From cebf60de35a47bd65707c1f0f5ec2b7991cd55a2 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Sat, 8 Mar 2025 11:08:21 +0100 Subject: [PATCH] Add SetDynamicVariable method to support dynamic variable creation This new method enables adding dynamic variables to the appropriate variable container if no predefined variable exists. It ensures flexibility in handling variables within the activity execution context while maintaining logical consistency. Minor formatting adjustments were also applied to improve code readability. --- .../ActivityExecutionContextExtensions.cs | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/modules/Elsa.Workflows.Core/Extensions/ActivityExecutionContextExtensions.cs b/src/modules/Elsa.Workflows.Core/Extensions/ActivityExecutionContextExtensions.cs index 91740adde..f229bee04 100644 --- a/src/modules/Elsa.Workflows.Core/Extensions/ActivityExecutionContextExtensions.cs +++ b/src/modules/Elsa.Workflows.Core/Extensions/ActivityExecutionContextExtensions.cs @@ -93,6 +93,31 @@ public static partial class ActivityExecutionContextExtensions public static Variable SetVariable(this ActivityExecutionContext context, string name, object? value, Action? configure = null) => context.ExpressionExecutionContext.SetVariable(name, value, configure); + public static Variable SetDynamicVariable(this ActivityExecutionContext context, string name, T value, Action? configure = null) + { + // Check if a predefined variable already exists. + var predefinedVariable = context.ExpressionExecutionContext.GetVariable(name); + + if (predefinedVariable != null) + { + context.SetVariable(name, value); + return predefinedVariable; + } + + // No predefined variable exists, so we will add a dynamic variable to the current container in scope. + var container = context.FindParentWithVariableContainer(); + + if (container == null) + throw new("No parent variable container found"); + + var existingVariable = container.DynamicVariables.FirstOrDefault(x => x.Name == name); + + if (existingVariable == null) + container.DynamicVariables.Add(new Variable(name, value)); + + return context.SetVariable(name, value); + } + /// /// Gets a workflow variable by name. /// @@ -140,7 +165,7 @@ public static partial class ActivityExecutionContextExtensions { var activity = node.Activity; var activityDescriptor = await activityRegistryLookup.FindAsync(activity.Type, activity.Version); - if (activityDescriptor != null && activityDescriptor.Outputs.Any()) + if (activityDescriptor != null && activityDescriptor.Outputs.Any()) yield return (activity, activityDescriptor); } } @@ -188,7 +213,10 @@ public static partial class ActivityExecutionContextExtensions /// public static async ValueTask SendSignalAsync(this ActivityExecutionContext context, object signal) { - var receivingContexts = new[] { context }.Concat(context.GetAncestors()).ToList(); + var receivingContexts = new[] + { + context + }.Concat(context.GetAncestors()).ToList(); var logger = context.GetRequiredService>(); var signalType = signal.GetType(); var signalTypeName = signalType.Name; @@ -243,7 +271,7 @@ public static partial class ActivityExecutionContextExtensions // Send a signal. await context.SendSignalAsync(new ScheduleActivityOutcomes(outcomes)); } - + /// /// Cancel the activity. For blocking activities, it means their bookmarks will be removed. For job activities, the background work will be cancelled. /// @@ -300,7 +328,7 @@ public static partial class ActivityExecutionContextExtensions return null; } - + /// /// Returns a flattened list of the current context's ancestors. ///