diff --git a/src/modules/Elsa.Workflows.Core/Activities/Composite.cs b/src/modules/Elsa.Workflows.Core/Activities/Composite.cs
index 6c9f047ec..ce42f19b1 100644
--- a/src/modules/Elsa.Workflows.Core/Activities/Composite.cs
+++ b/src/modules/Elsa.Workflows.Core/Activities/Composite.cs
@@ -1,5 +1,6 @@
using System.ComponentModel;
using Elsa.Expressions.Models;
+using Elsa.Workflows.Core.Activities.Flowchart.Models;
using Elsa.Workflows.Core.Attributes;
using Elsa.Workflows.Core.Models;
using Elsa.Workflows.Core.Services;
@@ -10,14 +11,18 @@ namespace Elsa.Workflows.Core.Activities;
///
/// Represents a composite activity that has a single activity. Like a workflow, but without workflow-level properties.
///
-[Activity("Elsa", "Workflows", "Execute a root activity that you can configure yourself")]
-public class Composite : ActivityBase
+public abstract class Composite : ActivityBase
{
+ ///
+ protected Composite()
+ {
+ OnSignalReceived(OnCompleteCompositeSignal);
+ }
+
///
/// The activity to schedule when this activity executes.
///
[Port]
- [Browsable(false)]
public IActivity Root { get; set; } = new Sequence();
///
@@ -39,16 +44,38 @@ public class Composite : ActivityBase
await OnCompletedAsync(context, childContext);
await context.CompleteActivityAsync();
}
+
+ ///
+ /// Completes this composite activity.
+ ///
+ protected async Task CompleteAsync(ActivityExecutionContext context, object? result = default) => await context.SendSignalAsync(new CompleteCompositeSignal(result));
+
+ ///
+ /// Completes this composite activity.
+ ///
+ protected async Task CompleteAsync(ActivityExecutionContext context, params string[] outcomes) => await CompleteAsync(context, new Outcomes(outcomes));
- protected virtual ValueTask OnCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext)
+ protected virtual ValueTask OnCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext)
{
OnCompleted(context, childContext);
return new();
}
- protected virtual void OnCompleted(ActivityExecutionContext context, ActivityExecutionContext childContext)
+ protected virtual void OnCompleted(ActivityExecutionContext context, ActivityExecutionContext childContext)
{
}
+
+ private async ValueTask OnCompleteCompositeSignal(CompleteCompositeSignal signal, SignalContext context)
+ {
+ var activityExecutionContext = context.ReceiverActivityExecutionContext;
+
+ // Remove the existing completed handler.
+ activityExecutionContext.WorkflowExecutionContext.PopCompletionCallback(activityExecutionContext, Root);
+
+ // Complete this activity.
+ await activityExecutionContext.CompleteActivityAsync(signal.Result);
+ context.StopPropagation();
+ }
protected static Inline From(Func activity) => new(activity);
protected static Inline From(Func activity) => new(activity);
@@ -82,7 +109,7 @@ public class Composite : ActivityBase
ConfigureActivities(context);
context.ScheduleActivity(Root, OnRootCompletedAsync);
}
-
+
///
/// Override this method to configure activity properties before execution.
///
@@ -106,6 +133,28 @@ public class Composite : ActivityBase
{
}
+ ///
+ /// Completes this composite activity.
+ ///
+ protected async Task CompleteAsync(ActivityExecutionContext context, object? result = default) => await context.SendSignalAsync(new CompleteCompositeSignal(result));
+
+ ///
+ /// Completes this composite activity.
+ ///
+ protected async Task CompleteAsync(ActivityExecutionContext context, params string[] outcomes) => await CompleteAsync(context, new Outcomes(outcomes));
+
+ private async ValueTask OnCompleteCompositeSignal(CompleteCompositeSignal signal, SignalContext context)
+ {
+ var activityExecutionContext = context.ReceiverActivityExecutionContext;
+
+ // Remove the existing completed handler.
+ activityExecutionContext.WorkflowExecutionContext.PopCompletionCallback(activityExecutionContext, Root);
+
+ // Complete this activity.
+ await activityExecutionContext.CompleteActivityAsync(signal.Result);
+ context.StopPropagation();
+ }
+
protected static Inline From(Func activity) => new(activity);
protected static Inline From(Func activity) => new(activity);
protected static Inline From(Action activity) => new(activity);
@@ -114,10 +163,4 @@ public class Composite : ActivityBase
protected static Inline From(Func> activity, MemoryBlockReference? output = default) => new(activity, output);
protected static Inline From(Func activity, MemoryBlockReference? output = default) => new(activity, output);
protected static Inline From(Func activity, MemoryBlockReference? output = default) => new(activity, output);
-
- private async ValueTask OnCompleteCompositeSignal(CompleteCompositeSignal signal, SignalContext context)
- {
- await context.ReceiverActivityExecutionContext.CompleteActivityAsync(signal.Result);
- context.StopPropagation();
- }
}
\ No newline at end of file
diff --git a/src/samples/aspnet/Elsa.Samples.TelnyxIntegration/GetAge.cs b/src/samples/aspnet/Elsa.Samples.TelnyxIntegration/GetAge.cs
index 734f40785..708103123 100644
--- a/src/samples/aspnet/Elsa.Samples.TelnyxIntegration/GetAge.cs
+++ b/src/samples/aspnet/Elsa.Samples.TelnyxIntegration/GetAge.cs
@@ -1,8 +1,5 @@
-using Elsa.Workflows.Core;
using Elsa.Workflows.Core.Activities;
using Elsa.Workflows.Core.Activities.Flowchart.Attributes;
-using Elsa.Workflows.Core.Activities.Flowchart.Models;
-using Elsa.Workflows.Core.Signals;
namespace Elsa.Samples.TelnyxIntegration;
@@ -16,7 +13,7 @@ public class GetAge : Composite
var random = new Random();
var n = random.Next(2);
var outcome = n == 0 ? "Under 18" : "Over 18";
- await context.SendSignalAsync(new CompleteCompositeSignal(new Outcomes(outcome)));
+ await CompleteAsync(context, outcome);
});
}
}
\ No newline at end of file