diff --git a/src/activities/Elsa.Activities.ControlFlow/Activities/ForEach.cs b/src/activities/Elsa.Activities.ControlFlow/Activities/ForEach.cs index 46a738c34d..664e4a3d29 100644 --- a/src/activities/Elsa.Activities.ControlFlow/Activities/ForEach.cs +++ b/src/activities/Elsa.Activities.ControlFlow/Activities/ForEach.cs @@ -55,7 +55,6 @@ protected override async Task OnExecuteAsync( if (index >= collection.Count) { - context.EndScope(); CurrentIndex = 0; return Done(); } @@ -63,11 +62,6 @@ protected override async Task OnExecuteAsync( var value = collection[index]; CurrentIndex++; - if (index == 0) - { - context.BeginScope(); - } - context.CurrentScope.SetVariable(IteratorName, value); return Outcome(OutcomeNames.Iterate); diff --git a/src/activities/Elsa.Activities.ControlFlow/Activities/While.cs b/src/activities/Elsa.Activities.ControlFlow/Activities/While.cs index a2093e7a45..edb825af8f 100644 --- a/src/activities/Elsa.Activities.ControlFlow/Activities/While.cs +++ b/src/activities/Elsa.Activities.ControlFlow/Activities/While.cs @@ -39,14 +39,10 @@ protected override async Task OnExecuteAsync( { var loop = await expressionEvaluator.EvaluateAsync(ConditionExpression, context, cancellationToken); - if (HasStarted) - context.EndScope(); - if (loop) { HasStarted = true; - - context.BeginScope(); + return Outcome(OutcomeNames.Iterate); } diff --git a/src/core/Elsa.Abstractions/Models/WorkflowInstance.cs b/src/core/Elsa.Abstractions/Models/WorkflowInstance.cs index 601ceecd63..9775d35196 100644 --- a/src/core/Elsa.Abstractions/Models/WorkflowInstance.cs +++ b/src/core/Elsa.Abstractions/Models/WorkflowInstance.cs @@ -16,7 +16,7 @@ public class WorkflowInstance public Instant? FaultedAt { get; set; } public Instant? AbortedAt { get; set; } public IDictionary Activities { get; set; } = new Dictionary(); - public Stack Scopes { get; set; } + public WorkflowExecutionScope Scope { get; set; } public Variables Input { get; set; } public HashSet BlockingActivities { get; set; } public ICollection ExecutionLog { get; set; } diff --git a/src/core/Elsa.Abstractions/Services/Models/Workflow.cs b/src/core/Elsa.Abstractions/Services/Models/Workflow.cs index d61409e8d2..3feae6b5cd 100644 --- a/src/core/Elsa.Abstractions/Services/Models/Workflow.cs +++ b/src/core/Elsa.Abstractions/Services/Models/Workflow.cs @@ -28,11 +28,9 @@ public Workflow( Input = new Variables(input ?? Variables.Empty); } - - public Workflow() { - Scopes = new Stack(new[] { new WorkflowExecutionScope() }); + Scope = new WorkflowExecutionScope(); BlockingActivities = new HashSet(); ExecutionLog = new List(); } @@ -48,7 +46,7 @@ public Workflow() public Instant? AbortedAt { get; set; } public ICollection Activities { get; } = new List(); public IList Connections { get; } = new List(); - public Stack Scopes { get; set; } + public WorkflowExecutionScope Scope { get; set; } public HashSet BlockingActivities { get; set; } public IList ExecutionLog { get; set; } public WorkflowFault Fault { get; set; } @@ -72,7 +70,7 @@ public WorkflowInstance ToInstance() FaultedAt = FaultedAt, AbortedAt = AbortedAt, Activities = activities, - Scopes = new Stack(Scopes), + Scope = Scope, BlockingActivities = new HashSet( BlockingActivities.Select(x => new BlockingActivity(x.Id, x.Type)), @@ -100,12 +98,11 @@ public void Initialize(WorkflowInstance instance) FaultedAt = instance.FaultedAt; AbortedAt = instance.AbortedAt; ExecutionLog = instance.ExecutionLog.ToList(); + Scope = instance.Scope; BlockingActivities = new HashSet(instance.BlockingActivities.Select(x => activityLookup[x.ActivityId])); - - Scopes = new Stack(instance.Scopes); - + foreach (var activity in Activities) { activity.State = new JObject(instance.Activities[activity.Id].State); diff --git a/src/core/Elsa.Abstractions/Services/Models/WorkflowExecutionContext.cs b/src/core/Elsa.Abstractions/Services/Models/WorkflowExecutionContext.cs index 914042f8b1..232ec1d04e 100644 --- a/src/core/Elsa.Abstractions/Services/Models/WorkflowExecutionContext.cs +++ b/src/core/Elsa.Abstractions/Services/Models/WorkflowExecutionContext.cs @@ -35,7 +35,7 @@ public WorkflowExecutionContext(Workflow workflowInstance, IClock clock, IServic public IEnumerable ScheduledActivities => scheduledActivities; public bool IsFirstPass { get; set; } public LogEntry CurrentLogEntry => Workflow.ExecutionLog.LastOrDefault(); - public WorkflowExecutionScope CurrentScope => Workflow.Scopes.Peek(); + public WorkflowExecutionScope CurrentScope => Workflow.Scope; public Variables TransientState { get; } = new Variables(); public IActivity CurrentActivity { get; private set; } public void ScheduleActivities(params IActivity[] activities) => ScheduleActivities((IEnumerable)activities); @@ -48,9 +48,6 @@ public void ScheduleActivities(IEnumerable activities) } } - public void BeginScope() => Workflow.Scopes.Push(new WorkflowExecutionScope()); - public void EndScope() => Workflow.Scopes.Pop(); - public void ScheduleActivity(IActivity activity) { scheduledActivities.Push(activity); @@ -62,21 +59,9 @@ public void ScheduleActivity(IActivity activity) public IActivity PopScheduledHaltingActivity() => scheduledHaltingActivities.Pop(); public IWorkflowExpressionEvaluator ExpressionEvaluator { get; } - public void SetVariable(string name, object value) - { - // Get the first scope (starting from the oldest one) containing the variable (existing variable). Otherwise use the current scope (new variable declaration) - var scope = Workflow.Scopes.Reverse().FirstOrDefault(x => x.Variables.ContainsKey(name)) ?? CurrentScope; - scope.SetVariable(name, value); - } - + public void SetVariable(string name, object value) => CurrentScope.SetVariable(name, value); public T GetVariable(string name) => (T) GetVariable(name); - - public object GetVariable(string name) - { - // Get the first scope (starting from the newest one) containing the variable. - var scope = Workflow.Scopes.FirstOrDefault(x => x.Variables.ContainsKey(name)) ?? CurrentScope; - return scope.GetVariable(name); - } + public object GetVariable(string name) => CurrentScope.GetVariable(name); public Task EvaluateAsync(IWorkflowExpression expression, CancellationToken cancellationToken) => ExpressionEvaluator.EvaluateAsync(expression, this, cancellationToken); @@ -123,9 +108,6 @@ public void Abort() Workflow.Status = WorkflowStatus.Aborted; } - public Variables GetVariables() => Workflow.Scopes - .Reverse() - .Select(x => x.Variables) - .Aggregate(Variables.Empty, (x, y) => new Variables(x.Union(y))); + public Variables GetVariables() => CurrentScope.Variables; } } \ No newline at end of file diff --git a/src/persistence/Elsa.Persistence.MongoDb/Extensions/ServiceCollectionExtensions.cs b/src/persistence/Elsa.Persistence.MongoDb/Extensions/ServiceCollectionExtensions.cs index b282c1c152..d4cca024cc 100644 --- a/src/persistence/Elsa.Persistence.MongoDb/Extensions/ServiceCollectionExtensions.cs +++ b/src/persistence/Elsa.Persistence.MongoDb/Extensions/ServiceCollectionExtensions.cs @@ -22,7 +22,7 @@ string connectionStringName ) { NodaTimeSerializers.Register(); - RegisterEnumAsStringConvention(); + RegisterConventions(); BsonSerializer.RegisterSerializer(new JObjectSerializer()); BsonSerializer.RegisterSerializer(new WorkflowExecutionScopeSerializer()); @@ -90,11 +90,17 @@ private static IMongoClient CreateDbClient(IConfiguration configuration, string return new MongoClient(connectionString); } - private static void RegisterEnumAsStringConvention() + private static void RegisterConventions() { var pack = new ConventionPack { new EnumRepresentationConvention(BsonType.String) }; ConventionRegistry.Register("EnumStringConvention", pack, _ => true); + + BsonClassMap.RegisterClassMap(cm => + { + cm.AutoMap(); + cm.SetIgnoreExtraElements(true); + }); } } } \ No newline at end of file