Fix access to container properties and improve object type conversion
This commit is contained in:
parent
f14c22d5d4
commit
67be790c7d
|
|
@ -1,4 +1,5 @@
|
|||
using System.ComponentModel;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using NodaTime;
|
||||
using NodaTime.Text;
|
||||
|
||||
|
|
@ -21,7 +22,10 @@ namespace Elsa
|
|||
return (T?)((object?)DurationPattern.JsonRoundtrip.Parse(value!.ToString()).Value)!;
|
||||
|
||||
var converter = TypeDescriptor.GetConverter(typeof(T));
|
||||
return converter.CanConvertFrom(value.GetType()) ? (T?) converter.ConvertFrom(value) : default;
|
||||
if (converter.CanConvertFrom(value.GetType()))
|
||||
return (T?)converter.ConvertFrom(value);
|
||||
|
||||
return (T?)Convert.ChangeType(value, typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -31,10 +31,18 @@ namespace Elsa.Services.Models
|
|||
public IServiceScope ServiceScope { get; }
|
||||
public IActivityBlueprint ActivityBlueprint { get; }
|
||||
public ActivityInstance ActivityInstance { get; }
|
||||
public ActivityInstance? ParentActivityInstance => WorkflowExecutionContext.WorkflowInstance.Activities.FirstOrDefault(x => x.Id == ActivityBlueprint.Parent?.Id);
|
||||
public IReadOnlyCollection<string> Outcomes { get; set; }
|
||||
public object? Input { get; }
|
||||
public CancellationToken CancellationToken { get; }
|
||||
public JObject Data => ActivityInstance.Data;
|
||||
public JObject? ParentData => ParentActivityInstance?.Data;
|
||||
|
||||
public T? GetParentState<T>(string key)
|
||||
{
|
||||
var parentData = ParentData;
|
||||
return parentData == null ? default : parentData.GetState<T>(key);
|
||||
}
|
||||
|
||||
public object? Output
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ namespace Elsa.Activities.ControlFlow
|
|||
public static IActivityBuilder Finish(this IBuilder builder, Func<ActivityExecutionContext, ValueTask<object?>> output) => builder.Finish(activity => activity.WithOutput(output));
|
||||
public static IActivityBuilder Finish(this IBuilder builder, Func<ActivityExecutionContext, object?> output) => builder.Finish(activity => activity.WithOutput(output));
|
||||
public static IActivityBuilder Finish(this IBuilder builder, Func<object?> output) => builder.Finish(activity => activity.WithOutput(output));
|
||||
public static IActivityBuilder Finish(this IBuilder builder, object? output) => builder.Finish(activity => activity.WithOutput(output));
|
||||
|
||||
public static IActivityBuilder Finish(this IBuilder builder, Func<ActivityExecutionContext, ValueTask<string?>> outcome) => builder.Finish(activity => activity.WithOutcome(outcome));
|
||||
public static IActivityBuilder Finish(this IBuilder builder, Func<ActivityExecutionContext, string?> outcome) => builder.Finish(activity => activity.WithOutcome(outcome));
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ namespace Elsa.Activities.ControlFlow
|
|||
if (loop)
|
||||
{
|
||||
CurrentValue = currentValue + Step;
|
||||
return Combine(Schedule(Id), Output(currentValue), Outcome(OutcomeNames.Iterate));
|
||||
return Outcome(OutcomeNames.Iterate, currentValue);
|
||||
}
|
||||
|
||||
CurrentValue = null;
|
||||
|
|
|
|||
|
|
@ -141,6 +141,11 @@ namespace Elsa.Builders
|
|||
var activityBlueprintDictionary = activityBlueprints.ToDictionary(x => x.Id);
|
||||
connections.AddRange(ConnectionBuilders.Select(x => new Connection(activityBlueprintDictionary[x.Source().ActivityId], activityBlueprintDictionary[x.Target().ActivityId], x.Outcome)));
|
||||
|
||||
|
||||
compositeActivityBlueprint.Connections = connections;
|
||||
compositeActivityBlueprint.Activities = activityBlueprints;
|
||||
compositeActivityBlueprint.ActivityPropertyProviders = new ActivityPropertyProviders(activityPropertyProviders);
|
||||
|
||||
// Build composite activities.
|
||||
var compositeActivityBuilders = activityBuilders.Where(x => typeof(CompositeActivity).IsAssignableFrom(x.ActivityType));
|
||||
BuildCompositeActivities(compositeActivityBuilders, activityBlueprints, connections, activityPropertyProviders);
|
||||
|
|
@ -150,10 +155,6 @@ namespace Elsa.Builders
|
|||
.Select(x => (x.ActivityId, x.PropertyValueProviders))
|
||||
.ToDictionary(x => x.ActivityId!, x => x.PropertyValueProviders!));
|
||||
|
||||
compositeActivityBlueprint.Connections = connections;
|
||||
compositeActivityBlueprint.Activities = activityBlueprints;
|
||||
compositeActivityBlueprint.ActivityPropertyProviders = new ActivityPropertyProviders(activityPropertyProviders);
|
||||
|
||||
return compositeActivityBlueprint;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ namespace Elsa.Services
|
|||
{
|
||||
public class ActivityFactory : IActivityFactory
|
||||
{
|
||||
public ActivityInstance Instantiate(IActivityBlueprint activityBlueprint) => new ActivityInstance(
|
||||
public ActivityInstance Instantiate(IActivityBlueprint activityBlueprint) => new(
|
||||
activityBlueprint.Id,
|
||||
activityBlueprint.Type,
|
||||
null,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using System.Runtime.CompilerServices;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.ActivityProviders;
|
||||
using Elsa.Exceptions;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
namespace Elsa.Services
|
||||
|
|
@ -19,8 +20,16 @@ namespace Elsa.Services
|
|||
}
|
||||
|
||||
public async ValueTask<IEnumerable<ActivityType>> GetActivityTypesAsync(CancellationToken cancellationToken) => (await GetDictionaryAsync(cancellationToken)).Values;
|
||||
public async ValueTask<ActivityType> GetActivityTypeAsync(string type, CancellationToken cancellationToken) => (await GetDictionaryAsync(cancellationToken))[type];
|
||||
|
||||
public async ValueTask<ActivityType> GetActivityTypeAsync(string type, CancellationToken cancellationToken)
|
||||
{
|
||||
var dictionary = await GetDictionaryAsync(cancellationToken);
|
||||
|
||||
if (!dictionary.ContainsKey(type))
|
||||
throw new WorkflowException($"The activity type '{type}' has not been registered. Did you forget to register it with ElsaOptions?");
|
||||
|
||||
return dictionary[type];
|
||||
}
|
||||
|
||||
public async ValueTask<RuntimeActivityInstance> ActivateActivityAsync(IActivityBlueprint activityBlueprint, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var type = await GetActivityTypeAsync(activityBlueprint.Type, cancellationToken);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
using Elsa.Activities.Console;
|
||||
using Elsa.Activities.ControlFlow;
|
||||
using Elsa.Activities.Timers;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Builders;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
using NodaTime;
|
||||
|
||||
namespace Elsa.Samples.ProgrammaticCompositeActivitiesConsole.Activities
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom activities that inherit from <seealso cref="CompositeActivity"/> declare their own mini-workflow.
|
||||
/// </summary>
|
||||
public class CountdownActivity : CompositeActivity
|
||||
{
|
||||
// Exposed properties on composite activities must store their values in the State property bag so that it gets persisted & available to child activities.
|
||||
// Activities are scheduled one by one, which means that when the child activities are executed, the container activity (such as this one) will not be in memory - the default value will be captured when the property is used directly.
|
||||
[ActivityProperty(Hint = "The start number.")]
|
||||
public int Start
|
||||
{
|
||||
get => GetState<int>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
public override void Build(ICompositeActivityBuilder activity)
|
||||
{
|
||||
activity
|
||||
.For(context => context.GetParentState<int>(nameof(Start)), _ => 0, _ => -1, iterate =>
|
||||
{
|
||||
iterate.WriteLine(context => $"{context.GetInput<int>()}...");
|
||||
}, Operator.GreaterThan)
|
||||
.WriteLine("Happy New Year!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ namespace Elsa.Samples.ProgrammaticCompositeActivitiesConsole.Activities
|
|||
/// Custom activities that inherit from <seealso cref="CompositeActivity"/> declare their own mini-workflow.
|
||||
/// </summary>
|
||||
[Action(Outcomes = new[] { "Left", "Right" })]
|
||||
public class CountDownActivity : CompositeActivity
|
||||
public class NavigateActivity : CompositeActivity
|
||||
{
|
||||
public override void Build(ICompositeActivityBuilder activity)
|
||||
{
|
||||
|
|
@ -3,6 +3,7 @@ using Elsa.Samples.ProgrammaticCompositeActivitiesConsole.Activities;
|
|||
using Elsa.Samples.ProgrammaticCompositeActivitiesConsole.Workflows;
|
||||
using Elsa.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Elsa.Samples.ProgrammaticCompositeActivitiesConsole
|
||||
{
|
||||
|
|
@ -12,9 +13,11 @@ namespace Elsa.Samples.ProgrammaticCompositeActivitiesConsole
|
|||
{
|
||||
// Create a service container with Elsa services.
|
||||
var services = new ServiceCollection()
|
||||
.AddLogging(logging => logging.AddConsole())
|
||||
.AddElsa(options => options
|
||||
.AddConsoleActivities()
|
||||
.AddActivity<CountDownActivity>()
|
||||
.AddActivity<NavigateActivity>()
|
||||
.AddActivity<CountdownActivity>()
|
||||
.AddWorkflow<CompositionWorkflow>())
|
||||
.BuildServiceProvider();
|
||||
|
||||
|
|
|
|||
|
|
@ -11,14 +11,15 @@ namespace Elsa.Samples.ProgrammaticCompositeActivitiesConsole.Workflows
|
|||
{
|
||||
public void Build(IWorkflowBuilder workflow) => workflow
|
||||
.WriteLine("Welcome to the Composite Activities demo workflow!")
|
||||
|
||||
|
||||
// A custom, composite activity
|
||||
.Then<CountDownActivity>(countDown =>
|
||||
.WriteLine("=Navigation demo=")
|
||||
.Then<NavigateActivity>(countDown =>
|
||||
{
|
||||
countDown.When("Left").WriteLine("Where going left!");
|
||||
countDown.When("Right").WriteLine("Where going right!");
|
||||
})
|
||||
.WriteLine("Done")
|
||||
;
|
||||
.WriteLine("=Countdown demo=")
|
||||
.Then<CountdownActivity>(activity => activity.Set(x => x.Start, 10));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue