From 3f173d64683f35a30ffdf08aa990ee210998b0e2 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Wed, 17 Feb 2021 21:43:16 +0100 Subject: [PATCH] Implement unwinding of Switch activity --- .../Activities/ControlFlow/Switch/Switch.cs | 40 ++++++++++++++++++- .../Elsa.Core/Services/ActivityActivator.cs | 4 ++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/core/Elsa.Core/Activities/ControlFlow/Switch/Switch.cs b/src/core/Elsa.Core/Activities/ControlFlow/Switch/Switch.cs index dfd018389..4d0d060d3 100644 --- a/src/core/Elsa.Core/Activities/ControlFlow/Switch/Switch.cs +++ b/src/core/Elsa.Core/Activities/ControlFlow/Switch/Switch.cs @@ -1,9 +1,14 @@ using System.Collections.Generic; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using Elsa.ActivityResults; using Elsa.Attributes; +using Elsa.Events; using Elsa.Services; using Elsa.Services.Models; +using MediatR; +using Newtonsoft.Json.Linq; // ReSharper disable once CheckNamespace namespace Elsa.Activities.ControlFlow @@ -14,7 +19,7 @@ namespace Elsa.Activities.ControlFlow Description = "Evaluate multiple conditions and continue execution depending on the results.", Outcomes = new[] { OutcomeNames.Done } )] - public class Switch : Activity + public class Switch : Activity, INotificationHandler { [ActivityProperty(Hint = "The conditions to evaluate.")] public ICollection Cases { get; set; } = new List(); @@ -27,9 +32,29 @@ namespace Elsa.Activities.ControlFlow get => GetState(); set => SetState(value); } + + public bool EnteredScope + { + get => GetState(); + set => SetState(value); + } protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context) { + if (!context.WorkflowInstance.Scopes.Contains(Id)) + { + if (!EnteredScope) + { + context.WorkflowInstance.Scopes.Push(Id); + EnteredScope = true; + } + else + { + EnteredScope = false; + return Done(); + } + } + if (Evaluated) { Evaluated = false; @@ -38,10 +63,21 @@ namespace Elsa.Activities.ControlFlow var matches = Cases.Where(x => x.Condition).Select(x => x.Name).ToList(); var results = Mode == SwitchMode.MatchFirst ? matches.Any() ? new[] { matches.First() } : new string[0] : matches.ToArray(); - var outcomes = new[] { OutcomeNames.Done }.Concat(results); + var outcomes = results; Evaluated = true; return Outcomes(outcomes); } + + public Task Handle(ScopeEvicted notification, CancellationToken cancellationToken) + { + if (notification.EvictedScope.Type != nameof(Switch)) + return Task.CompletedTask; + + var data = notification.WorkflowExecutionContext.WorkflowInstance.ActivityData.GetItem(notification.EvictedScope.Id, () => new JObject()); + data.SetState(nameof(EnteredScope), false); + + return Task.CompletedTask; + } } } \ No newline at end of file diff --git a/src/core/Elsa.Core/Services/ActivityActivator.cs b/src/core/Elsa.Core/Services/ActivityActivator.cs index 64eb039ea..be0f93ba2 100644 --- a/src/core/Elsa.Core/Services/ActivityActivator.cs +++ b/src/core/Elsa.Core/Services/ActivityActivator.cs @@ -34,11 +34,15 @@ namespace Elsa.Services if (IsReturningIfElse(activity)) return false; + + if (IsReturningSwitch(activity)) + return false; return true; } private bool IsReturningComposite(IActivity activity) => activity is CompositeActivity && activity.Data.GetState(nameof(CompositeActivity.IsScheduled)); private bool IsReturningIfElse(IActivity activity) => activity is IfElse && activity.Data.GetState(nameof(IfElse.EnteredScope)); + private bool IsReturningSwitch(IActivity activity) => activity is Switch && activity.Data.GetState(nameof(Switch.EnteredScope)); } } \ No newline at end of file