Add support for composite activities to return outcomes
This commit is contained in:
parent
055482b935
commit
dadee53d2d
|
|
@ -16,18 +16,18 @@ namespace Elsa.ActivityResults
|
|||
|
||||
Outcomes = outcomeList;
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<string> Outcomes { get; }
|
||||
|
||||
public IEnumerable<string> Outcomes { get; }
|
||||
|
||||
protected override void Execute(ActivityExecutionContext activityExecutionContext)
|
||||
{
|
||||
activityExecutionContext.Outcomes = Outcomes.ToList();
|
||||
|
||||
var outcomes = activityExecutionContext.Outcomes = Outcomes.ToList();
|
||||
var workflowExecutionContext = activityExecutionContext.WorkflowExecutionContext;
|
||||
|
||||
var nextActivities = GetNextActivities(
|
||||
workflowExecutionContext,
|
||||
activityExecutionContext.ActivityBlueprint.Id,
|
||||
Outcomes).ToList();
|
||||
outcomes).ToList();
|
||||
|
||||
workflowExecutionContext.ScheduleActivities(nextActivities, activityExecutionContext.Output);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,35 +21,35 @@ namespace Elsa.Services
|
|||
public bool PersistWorkflow { get; set; }
|
||||
public bool LoadWorkflowContext { get; set; }
|
||||
public bool SaveWorkflowContext { get; set; }
|
||||
public JObject Data { get; set; } = new JObject();
|
||||
public JObject Data { get; set; } = new();
|
||||
public ValueTask<bool> CanExecuteAsync(ActivityExecutionContext context, CancellationToken cancellationToken) => OnCanExecuteAsync(context, cancellationToken);
|
||||
public ValueTask<IActivityExecutionResult> ExecuteAsync(ActivityExecutionContext context, CancellationToken cancellationToken) => OnExecuteAsync(context, cancellationToken);
|
||||
public ValueTask<IActivityExecutionResult> ResumeAsync(ActivityExecutionContext context, CancellationToken cancellationToken) => OnResumeAsync(context, cancellationToken);
|
||||
protected virtual ValueTask<bool> OnCanExecuteAsync(ActivityExecutionContext context, CancellationToken cancellationToken) => new ValueTask<bool>(OnCanExecute(context));
|
||||
protected virtual ValueTask<IActivityExecutionResult> OnExecuteAsync(ActivityExecutionContext context, CancellationToken cancellationToken) => new ValueTask<IActivityExecutionResult>(OnExecute(context));
|
||||
protected virtual ValueTask<IActivityExecutionResult> OnResumeAsync(ActivityExecutionContext context, CancellationToken cancellationToken) => new ValueTask<IActivityExecutionResult>(OnResume(context));
|
||||
protected virtual ValueTask<bool> OnCanExecuteAsync(ActivityExecutionContext context, CancellationToken cancellationToken) => new(OnCanExecute(context));
|
||||
protected virtual ValueTask<IActivityExecutionResult> OnExecuteAsync(ActivityExecutionContext context, CancellationToken cancellationToken) => new(OnExecute(context));
|
||||
protected virtual ValueTask<IActivityExecutionResult> OnResumeAsync(ActivityExecutionContext context, CancellationToken cancellationToken) => new(OnResume(context));
|
||||
protected virtual bool OnCanExecute(ActivityExecutionContext context) => true;
|
||||
protected virtual IActivityExecutionResult OnExecute(ActivityExecutionContext context) => OnExecute();
|
||||
protected virtual IActivityExecutionResult OnExecute() => Done();
|
||||
protected virtual IActivityExecutionResult OnResume(ActivityExecutionContext context) => OnResume();
|
||||
protected virtual IActivityExecutionResult OnResume() => Done();
|
||||
protected NoopResult Noop() => new NoopResult();
|
||||
protected NoopResult Noop() => new();
|
||||
protected OutcomeResult Done() => Outcome(OutcomeNames.Done);
|
||||
protected CombinedResult Done(object? output) => Combine(Output(output), Done());
|
||||
protected OutcomeResult Outcomes(IEnumerable<string> outcomes) => new OutcomeResult(outcomes);
|
||||
protected OutcomeResult Outcomes(IEnumerable<string> outcomes) => new(outcomes);
|
||||
protected OutcomeResult Outcomes(params string[] outcomes) => Outcomes((IEnumerable<string>)outcomes);
|
||||
protected OutcomeResult Outcome(string outcome) => Outcomes(outcome);
|
||||
protected CombinedResult Outcome(string outcome, object? output) => Combine(Output(output), Outcome(outcome));
|
||||
protected OutputResult Output(object? output) => new OutputResult(output);
|
||||
protected SuspendResult Suspend() => new SuspendResult();
|
||||
protected ScheduleActivitiesResult Schedule(params string[] activityIds) => new ScheduleActivitiesResult(activityIds);
|
||||
protected ScheduleActivitiesResult Schedule(IEnumerable<string> activityIds, object input) => new ScheduleActivitiesResult(activityIds, input);
|
||||
protected OutputResult Output(object? output) => new(output);
|
||||
protected SuspendResult Suspend() => new();
|
||||
protected ScheduleActivitiesResult Schedule(params string[] activityIds) => new(activityIds);
|
||||
protected ScheduleActivitiesResult Schedule(IEnumerable<string> activityIds, object input) => new(activityIds, input);
|
||||
protected ScheduleActivitiesResult Schedule(string activityId, object input) => Schedule(new[] { activityId }, input);
|
||||
protected ScheduleActivitiesResult Schedule(IEnumerable<ScheduledActivity> activities) => new ScheduleActivitiesResult(activities);
|
||||
protected PostScheduleActivitiesResult PostSchedule(params string[] activityIds) => new PostScheduleActivitiesResult(activityIds);
|
||||
protected CombinedResult Combine(IEnumerable<IActivityExecutionResult> results) => new CombinedResult(results);
|
||||
protected CombinedResult Combine(params IActivityExecutionResult[] results) => new CombinedResult(results);
|
||||
protected FaultResult Fault(LocalizedString message) => new FaultResult(message);
|
||||
protected ScheduleActivitiesResult Schedule(IEnumerable<ScheduledActivity> activities) => new(activities);
|
||||
protected PostScheduleActivitiesResult PostSchedule(params string[] activityIds) => new(activityIds);
|
||||
protected CombinedResult Combine(IEnumerable<IActivityExecutionResult> results) => new(results);
|
||||
protected CombinedResult Combine(params IActivityExecutionResult[] results) => new(results);
|
||||
protected FaultResult Fault(LocalizedString message) => new(message);
|
||||
|
||||
protected T GetState<T>(Func<T>? defaultValue = null, [CallerMemberName] string name = null!) => Data.GetState(name, defaultValue);
|
||||
protected T GetState<T>(Type type, Func<T>? defaultValue = null, [CallerMemberName] string name = null!) => Data.GetState(type, name, defaultValue);
|
||||
|
|
|
|||
|
|
@ -11,11 +11,24 @@ namespace Elsa.Services
|
|||
{
|
||||
}
|
||||
|
||||
private bool IsScheduled
|
||||
{
|
||||
get => GetState<bool>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context)
|
||||
{
|
||||
if (IsScheduled)
|
||||
return Complete(context);
|
||||
|
||||
var compositeActivityBlueprint = (ICompositeActivityBlueprint)context.ActivityBlueprint;
|
||||
var startActivities = compositeActivityBlueprint.GetStartActivities().Select(x => x.Id).ToList();
|
||||
return Combine(Done(), Schedule(startActivities, null!));
|
||||
context.WorkflowExecutionContext.PostScheduleActivity(Id);
|
||||
IsScheduled = true;
|
||||
return Schedule(startActivities, null!);
|
||||
}
|
||||
|
||||
protected virtual IActivityExecutionResult Complete(ActivityExecutionContext context) => Done();
|
||||
}
|
||||
}
|
||||
|
|
@ -89,11 +89,7 @@ namespace Elsa.Services.Models
|
|||
WorkflowFault = new WorkflowFault(activityId, message);
|
||||
}
|
||||
|
||||
public void Complete(object? output = default)
|
||||
{
|
||||
WorkflowInstance.Status = WorkflowStatus.Finished;
|
||||
WorkflowInstance.Output = output;
|
||||
}
|
||||
public void Complete() => WorkflowInstance.Status = WorkflowStatus.Finished;
|
||||
|
||||
public IActivityBlueprint? GetActivityBlueprintById(string id) => WorkflowBlueprint.Activities.FirstOrDefault(x => x.Id == id);
|
||||
public IActivityBlueprint? GetActivityBlueprintByName(string name) => WorkflowBlueprint.Activities.FirstOrDefault(x => x.Name == name);
|
||||
|
|
|
|||
|
|
@ -18,9 +18,8 @@ namespace Elsa.Activities.ControlFlow
|
|||
protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context)
|
||||
{
|
||||
context.WorkflowExecutionContext.WorkflowInstance.BlockingActivities.Clear();
|
||||
context.WorkflowExecutionContext.Complete(OutputValue);
|
||||
|
||||
return Combine(Done(OutputValue));
|
||||
return Done(OutputValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -85,7 +85,7 @@ namespace Elsa.Builders
|
|||
where T : class, IActivity
|
||||
{
|
||||
var activityBuilder = new ActivityBuilder(typeof(T), this, propertyValueProviders);
|
||||
return Add(activityBuilder);
|
||||
return Add(activityBuilder, branch);
|
||||
}
|
||||
|
||||
public IActivityBuilder Add(
|
||||
|
|
|
|||
|
|
@ -280,6 +280,7 @@ namespace Elsa.Services
|
|||
await _mediator.Publish(new ActivityExecuting(activityExecutionContext), cancellationToken);
|
||||
await result.ExecuteAsync(activityExecutionContext, cancellationToken);
|
||||
await _mediator.Publish(new ActivityExecuted(activityExecutionContext), cancellationToken);
|
||||
workflowExecutionContext.WorkflowInstance.Output = activityExecutionContext.Output;
|
||||
workflowExecutionContext.WorkflowInstance.ContextId = await SaveWorkflowContextAsync(workflowExecutionContext, WorkflowContextFidelity.Activity, activityBlueprint.SaveWorkflowContext, cancellationToken);
|
||||
|
||||
activityOperation = Execute;
|
||||
|
|
|
|||
|
|
@ -1,20 +1,27 @@
|
|||
using Elsa.Activities.Console;
|
||||
using Elsa.Activities.ControlFlow;
|
||||
using Elsa.ActivityResults;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Builders;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
namespace Elsa.Samples.ProgrammaticCompositeActivitiesConsole.Activities
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom activities that inherit from <seealso cref="CompositeActivity"/> declare their own mini-workflow.
|
||||
/// </summary>
|
||||
[Action(Outcomes = new[] { "Left", "Right" })]
|
||||
public class CountDownActivity : CompositeActivity
|
||||
{
|
||||
public override void Build(ICompositeActivityBuilder composite)
|
||||
{
|
||||
composite
|
||||
.WriteLine("3!")
|
||||
.WriteLine("2!")
|
||||
.WriteLine("1!");
|
||||
.WriteLine("Turn left or right?")
|
||||
.ReadLine()
|
||||
.Finish(context => (string) context.Input);
|
||||
}
|
||||
|
||||
protected override IActivityExecutionResult Complete(ActivityExecutionContext context) => Outcome(((string) context.WorkflowExecutionContext.WorkflowInstance.Output)!);
|
||||
}
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@ namespace Elsa.Samples.ProgrammaticCompositeActivitiesConsole
|
|||
await startupRunner.StartupAsync();
|
||||
|
||||
// Get a workflow host.
|
||||
var workflowRunner = services.GetService<IWorkflowRunner>();
|
||||
var workflowRunner = services.GetRequiredService<IWorkflowRunner>();
|
||||
|
||||
// Execute the workflow.
|
||||
await workflowRunner.RunWorkflowAsync<CompositionWorkflow>();
|
||||
|
|
|
|||
|
|
@ -13,8 +13,10 @@ namespace Elsa.Samples.ProgrammaticCompositeActivitiesConsole.Workflows
|
|||
.WriteLine("Welcome to the Composite Activities demo workflow!")
|
||||
|
||||
// A custom, composite activity
|
||||
.Then<CountDownActivity>()
|
||||
|
||||
.WriteLine("Done!");
|
||||
.Then<CountDownActivity>(countDown =>
|
||||
{
|
||||
countDown.When("Left").WriteLine("We're going left.");
|
||||
countDown.When("Right").WriteLine("We're going right.");
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue