adding set var and main/sub workflow tests (#3855)
* Adding set var and main/sub workflow tests * Deprecate SetWorkflowOutput and replace with SetOutput --------- Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
This commit is contained in:
parent
8390efc332
commit
dd919a4000
|
|
@ -1,4 +1,4 @@
|
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=abcdefghijklmnopqrstuvwxyz/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Deconstructor/@EntryIndexedValue">True</s:Boolean>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ public static class ActivityDescriptorExtensions
|
|||
public static IDictionary<string, Input?> GetWrappedInputProperties(this ActivityDescriptor activityDescriptor, IActivity activity)
|
||||
{
|
||||
var wrappedInputDescriptors = activityDescriptor.Inputs.Where(x => x.IsWrapped).ToList();
|
||||
var inputLookup = wrappedInputDescriptors.ToDictionary(x => x.Name, x => (Input?)x.ValueAccessor(activity));
|
||||
var inputLookup = wrappedInputDescriptors.ToDictionary(x => x.Name, x => (Input?)x.ValueGetter(activity));
|
||||
return inputLookup;
|
||||
}
|
||||
|
||||
|
|
@ -33,6 +33,6 @@ public static class ActivityDescriptorExtensions
|
|||
public static Input? GetWrappedInputProperty(this ActivityDescriptor activityDescriptor, IActivity activity, string name)
|
||||
{
|
||||
var inputDescriptor = activityDescriptor.Inputs.FirstOrDefault(x => x.Name == name && x.IsWrapped);
|
||||
return inputDescriptor?.ValueAccessor(activity) as Input;
|
||||
return inputDescriptor?.ValueGetter(activity) as Input;
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ public class InputDescriptor : PropertyDescriptor
|
|||
public InputDescriptor(
|
||||
string name,
|
||||
Type type,
|
||||
Func<IActivity, object?> valueAccessor,
|
||||
Func<IActivity, object?> valueGetter,
|
||||
bool isWrapped,
|
||||
string uiHint,
|
||||
string displayName,
|
||||
|
|
@ -35,7 +35,7 @@ public class InputDescriptor : PropertyDescriptor
|
|||
{
|
||||
Name = name;
|
||||
Type = type;
|
||||
ValueAccessor = valueAccessor;
|
||||
ValueGetter = valueGetter;
|
||||
IsWrapped = isWrapped;
|
||||
UIHint = uiHint;
|
||||
DisplayName = displayName;
|
||||
|
|
@ -52,12 +52,6 @@ public class InputDescriptor : PropertyDescriptor
|
|||
IsBrowsable = isBrowsable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of the input property for the specified activity.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public Func<IActivity, object?> ValueAccessor { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// True if the property is wrapped with an <see cref="Input{T}"/> type, false otherwise.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
using System.Text.Json.Serialization;
|
||||
using Elsa.Workflows.Core.Contracts;
|
||||
|
||||
namespace Elsa.Workflows.Core.Models;
|
||||
|
||||
public class OutputDescriptor : PropertyDescriptor
|
||||
|
|
@ -10,12 +13,14 @@ public class OutputDescriptor : PropertyDescriptor
|
|||
string name,
|
||||
string displayName,
|
||||
Type type,
|
||||
Func<IActivity, object?> valueGetter,
|
||||
string? description = default,
|
||||
bool? isBrowsable = default)
|
||||
{
|
||||
Name = name;
|
||||
DisplayName = displayName;
|
||||
Type = type;
|
||||
ValueGetter = valueGetter;
|
||||
Description = description;
|
||||
IsBrowsable = isBrowsable;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Text.Json.Serialization;
|
||||
using Elsa.Workflows.Core.Contracts;
|
||||
|
||||
namespace Elsa.Workflows.Core.Models;
|
||||
|
||||
|
|
@ -11,34 +12,41 @@ public abstract class PropertyDescriptor
|
|||
/// The name.
|
||||
/// </summary>
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The .NET type.
|
||||
/// </summary>
|
||||
[JsonPropertyName("typeName")]public Type Type { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("typeName")]
|
||||
public Type Type { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The user friendly name of the input. Used by UI tools.
|
||||
/// </summary>
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The user friendly description of the input. Used by UI tools.
|
||||
/// </summary>
|
||||
public string? Description { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The order in which this input should be displayed by UI tools.
|
||||
/// </summary>
|
||||
public float Order { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// True if this input should be displayed by UI tools, false otherwise.
|
||||
/// </summary>
|
||||
public bool? IsBrowsable { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// True if this input property is synthetic, which means it does not exist physically on the activity's .NET type.
|
||||
/// </summary>
|
||||
public bool IsSynthetic { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of the input property for the specified activity.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public Func<IActivity, object?> ValueGetter { get; set; } = default!;
|
||||
}
|
||||
|
|
@ -116,6 +116,7 @@ public class ActivityDescriber : IActivityDescriber
|
|||
(outputAttribute?.Name ?? propertyInfo.Name).Pascalize(),
|
||||
outputAttribute?.DisplayName ?? propertyInfo.Name.Humanize(LetterCasing.Title),
|
||||
wrappedPropertyType,
|
||||
propertyInfo.GetValue,
|
||||
descriptionAttribute?.Description ?? outputAttribute?.Description,
|
||||
outputAttribute?.IsBrowsable ?? true
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Core;
|
||||
using Elsa.Workflows.Core.Attributes;
|
||||
using Elsa.Workflows.Core.Models;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Workflows.Management.Activities.SetOutput;
|
||||
|
||||
/// <summary>
|
||||
/// Assigns a given value to a workflow definition's output.
|
||||
/// </summary>
|
||||
[Activity("Elsa", "Composition", "Assigns a given value to a the container's output.", Kind = ActivityKind.Action)]
|
||||
[PublicAPI]
|
||||
public class SetOutput : CodeActivity
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the output to assign.
|
||||
/// </summary>
|
||||
[Input(
|
||||
DisplayName = "Output",
|
||||
Description = "The output to assign.",
|
||||
UIHint = InputUIHints.OutputPicker
|
||||
)]
|
||||
public Input<string> OutputName { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The value to assign to the output.
|
||||
/// </summary>
|
||||
[Input(Description = "The value to assign.")]
|
||||
public Input<object?> OutputValue { get; set; } = default!;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Execute(ActivityExecutionContext context)
|
||||
{
|
||||
var outputName = OutputName.Get(context);
|
||||
var ancestorContext = context.GetAncestors().FirstOrDefault(x => x.ActivityDescriptor.Outputs.Any(y => y.Name == outputName));
|
||||
|
||||
if (ancestorContext != null)
|
||||
SetAncestorActivityOutput(context, ancestorContext);
|
||||
}
|
||||
|
||||
private void SetAncestorActivityOutput(ActivityExecutionContext context, ActivityExecutionContext ancestorContext)
|
||||
{
|
||||
var ancestorActivity = ancestorContext.Activity;
|
||||
var ancestorActivityDescriptor = ancestorContext.ActivityDescriptor;
|
||||
var outputName = OutputName.Get(context);
|
||||
var ancestorOutputDescriptor = ancestorActivityDescriptor.Outputs.FirstOrDefault(x => x.Name == outputName);
|
||||
|
||||
if (ancestorOutputDescriptor == null)
|
||||
return;
|
||||
|
||||
var outputValue = OutputValue.GetOrDefault(context);
|
||||
var ancestorOutput = (Output)ancestorOutputDescriptor.ValueGetter(ancestorActivity)!;
|
||||
ancestorContext.Set(ancestorOutput, outputValue);
|
||||
|
||||
// If the ancestor activity is the root workflow, we need to update the workflow execution context's output collection as well.
|
||||
if (ancestorContext.ParentActivityExecutionContext == null)
|
||||
context.WorkflowExecutionContext.Output[outputName] = outputValue!;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
using Elsa.Common.Models;
|
||||
using System.ComponentModel;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Core;
|
||||
using Elsa.Workflows.Core.Attributes;
|
||||
using Elsa.Workflows.Core.Models;
|
||||
using Elsa.Workflows.Management.Contracts;
|
||||
using Elsa.Workflows.Management.Extensions;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Workflows.Management.Activities.SetWorkflowOutput;
|
||||
|
|
@ -12,8 +10,10 @@ namespace Elsa.Workflows.Management.Activities.SetWorkflowOutput;
|
|||
/// <summary>
|
||||
/// Assigns a given value to a workflow definition's output.
|
||||
/// </summary>
|
||||
[Activity("Elsa", "Composition", "Assigns a given value to a workflow definition's output.", Kind = ActivityKind.Action)]
|
||||
[Activity("Elsa", "Obsolete", "[OBSOLETE] Assigns a given value to a workflow definition's output.", Kind = ActivityKind.Action)]
|
||||
[PublicAPI]
|
||||
[Obsolete("Use the SetOutput activity instead.")]
|
||||
[Browsable(false)]
|
||||
public class SetWorkflowOutput : CodeActivity
|
||||
{
|
||||
/// <summary>
|
||||
|
|
@ -34,49 +34,29 @@ public class SetWorkflowOutput : CodeActivity
|
|||
/// <inheritdoc />
|
||||
protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
|
||||
{
|
||||
// Get the first workflow definition activity in scope, so that we can get its output definitions.
|
||||
var workflowDefinitionActivityContext = context.GetFirstWorkflowDefinitionActivityExecutionContext();
|
||||
var outputName = OutputName.Get(context);
|
||||
var ancestorContext = context.GetAncestors().FirstOrDefault(x => x.ActivityDescriptor.Outputs.Any(y => y.Name == outputName));
|
||||
|
||||
if (workflowDefinitionActivityContext != null)
|
||||
// Set the output on the first workflow definition activity execution context in scope.
|
||||
await SetWorkflowDefinitionActivityOutputAsync(context, workflowDefinitionActivityContext);
|
||||
else
|
||||
// If no workflow definition activity is in scope, set the output on the workflow execution context.
|
||||
SetWorkflowDefinitionOutput(context);
|
||||
if (ancestorContext != null)
|
||||
SetAncestorActivityOutput(context, ancestorContext);
|
||||
}
|
||||
|
||||
private void SetWorkflowDefinitionOutput(ActivityExecutionContext context)
|
||||
private void SetAncestorActivityOutput(ActivityExecutionContext context, ActivityExecutionContext ancestorContext)
|
||||
{
|
||||
var ancestorActivity = ancestorContext.Activity;
|
||||
var ancestorActivityDescriptor = ancestorContext.ActivityDescriptor;
|
||||
var outputName = OutputName.Get(context);
|
||||
var workflowActivityContext = context.GetAncestors().Last(x => x.Activity is Workflow);
|
||||
var outputValue = OutputValue.Get(context);
|
||||
workflowActivityContext.WorkflowExecutionContext.Output[outputName] = outputValue!;
|
||||
}
|
||||
var ancestorOutputDescriptor = ancestorActivityDescriptor.Outputs.FirstOrDefault(x => x.Name == outputName);
|
||||
|
||||
private async Task SetWorkflowDefinitionActivityOutputAsync(ActivityExecutionContext context, ActivityExecutionContext workflowDefinitionActivityContext)
|
||||
{
|
||||
var workflowDefinitionStore = context.GetRequiredService<IWorkflowDefinitionStore>();
|
||||
var workflowDefinitionActivity = (WorkflowDefinitionActivity.WorkflowDefinitionActivity)workflowDefinitionActivityContext.Activity;
|
||||
var definitionId = workflowDefinitionActivity.WorkflowDefinitionId;
|
||||
var versionOptions = VersionOptions.SpecificVersion(workflowDefinitionActivity.Version);
|
||||
var filter = new WorkflowDefinitionFilter { DefinitionId = definitionId, VersionOptions = versionOptions};
|
||||
var workflowDefinition = await workflowDefinitionStore.FindAsync(filter, context.CancellationToken);
|
||||
|
||||
if (workflowDefinition == null)
|
||||
return;
|
||||
|
||||
var outputName = OutputName.Get(context);
|
||||
var outputDescriptor = workflowDefinition.Outputs.FirstOrDefault(x => x.Name == outputName);
|
||||
|
||||
if (outputDescriptor == null)
|
||||
return;
|
||||
|
||||
var output = workflowDefinitionActivity.SyntheticProperties.TryGetValue(outputDescriptor.Name, out var outputProp) ? (Output)outputProp : default;
|
||||
|
||||
if (output == null)
|
||||
if (ancestorOutputDescriptor == null)
|
||||
return;
|
||||
|
||||
var outputValue = OutputValue.GetOrDefault(context);
|
||||
context.Set(output, outputValue);
|
||||
var ancestorOutput = (Output)ancestorOutputDescriptor.ValueGetter(ancestorActivity)!;
|
||||
ancestorContext.Set(ancestorOutput, outputValue);
|
||||
|
||||
// If the ancestor activity is the root workflow, we need to update the workflow execution context's output collection as well.
|
||||
if (ancestorContext.ParentActivityExecutionContext == null)
|
||||
context.WorkflowExecutionContext.Output[outputName] = outputValue!;
|
||||
}
|
||||
}
|
||||
|
|
@ -106,7 +106,7 @@ public class WorkflowDefinitionActivityProvider : IActivityProvider
|
|||
{
|
||||
Type = nakedType,
|
||||
IsWrapped = true,
|
||||
ValueAccessor = activity => ((WorkflowDefinitionActivity)activity).SyntheticProperties.GetValueOrDefault(inputDefinition.Name),
|
||||
ValueGetter = activity => ((WorkflowDefinitionActivity)activity).SyntheticProperties.GetValueOrDefault(inputDefinition.Name),
|
||||
Name = inputDefinition.Name,
|
||||
DisplayName = inputDefinition.DisplayName,
|
||||
Description = inputDefinition.Description,
|
||||
|
|
@ -129,6 +129,7 @@ public class WorkflowDefinitionActivityProvider : IActivityProvider
|
|||
return new OutputDescriptor
|
||||
{
|
||||
Type = nakedType,
|
||||
ValueGetter = activity => ((WorkflowDefinitionActivity)activity).SyntheticProperties.GetValueOrDefault(outputDefinition.Name),
|
||||
Name = outputDefinition.Name,
|
||||
DisplayName = outputDefinition.DisplayName,
|
||||
Description = outputDefinition.Description,
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Core.Models;
|
||||
using Elsa.Workflows.Management.Activities.WorkflowDefinitionActivity;
|
||||
|
||||
namespace Elsa.Workflows.Management.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Extends the <see cref="ActivityExecutionContext"/>.
|
||||
/// </summary>
|
||||
public static class ActivityExecutionContextExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the first <see cref="WorkflowDefinitionActivity"/> in scope of the specified <see cref="ActivityExecutionContext"/>.
|
||||
/// </summary>
|
||||
public static WorkflowDefinitionActivity? GetFirstWorkflowDefinitionActivity(this ActivityExecutionContext context)
|
||||
{
|
||||
var workflowDefinitionActivityContext = context.GetFirstWorkflowDefinitionActivityExecutionContext();
|
||||
return (WorkflowDefinitionActivity?)workflowDefinitionActivityContext?.Activity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the first <see cref="WorkflowDefinitionActivity"/> in scope of the specified <see cref="ActivityExecutionContext"/>.
|
||||
/// </summary>
|
||||
public static ActivityExecutionContext? GetFirstWorkflowDefinitionActivityExecutionContext(this ActivityExecutionContext context) =>
|
||||
context.GetAncestors().FirstOrDefault(x => x.Activity is WorkflowDefinitionActivity);
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Testing.Shared;
|
||||
using Elsa.Workflows.Core.Contracts;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Elsa.IntegrationTests.Scenarios.CompositesPassingData;
|
||||
|
||||
public class Tests
|
||||
{
|
||||
private readonly IWorkflowRunner _workflowRunner;
|
||||
private readonly CapturingTextWriter _capturingTextWriter = new();
|
||||
private readonly IWorkflowBuilderFactory _workflowBuilderFactory;
|
||||
|
||||
public Tests(ITestOutputHelper testOutputHelper)
|
||||
{
|
||||
var services = new TestApplicationBuilder(testOutputHelper)
|
||||
.WithCapturingTextWriter(_capturingTextWriter)
|
||||
.ConfigureElsa(elsa => elsa.UseJavaScript())
|
||||
.Build();
|
||||
_workflowBuilderFactory = services.GetRequiredService<IWorkflowBuilderFactory>();
|
||||
_workflowRunner = services.GetRequiredService<IWorkflowRunner>();
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "The main workflow can capture the result of the composite activity")]
|
||||
public async Task Test1()
|
||||
{
|
||||
var workflow = await _workflowBuilderFactory.CreateBuilder().BuildWorkflowAsync<AddTextMainWorkflow>();
|
||||
|
||||
// Start workflow.
|
||||
await _workflowRunner.RunAsync(workflow);
|
||||
|
||||
// Verify expected output.
|
||||
var line = _capturingTextWriter.Lines.ToList().Last();
|
||||
Assert.Equal("hi there obi wan", line);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Core.Abstractions;
|
||||
using Elsa.Workflows.Core.Activities;
|
||||
using Elsa.Workflows.Core.Contracts;
|
||||
using Elsa.Workflows.Core.Models;
|
||||
using Elsa.Workflows.Management.Activities.SetOutput;
|
||||
using Elsa.Workflows.Management.Activities.SetWorkflowOutput;
|
||||
|
||||
namespace Elsa.IntegrationTests.Scenarios.CompositesPassingData;
|
||||
|
||||
/// <summary>
|
||||
/// A composite activity that adds text to a string
|
||||
/// </summary>
|
||||
public class AddTextSubWorkflow : Composite
|
||||
{
|
||||
public Input<string> A { get; set; } = default!;
|
||||
public Output<string> B { get; set; } = default!;
|
||||
|
||||
public AddTextSubWorkflow()
|
||||
{
|
||||
var setOutput = new SetOutput()
|
||||
{
|
||||
OutputName = new Input<string>("B"),
|
||||
OutputValue = new Input<object?>(context => "hi there " + A.Get(context))
|
||||
};
|
||||
|
||||
Root = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
setOutput
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A workflow that uses the <see cref="AddTextSubWorkflow"/> composite activity.
|
||||
/// </summary>
|
||||
public class AddTextMainWorkflow : WorkflowBase
|
||||
{
|
||||
protected override void Build(IWorkflowBuilder workflow)
|
||||
{
|
||||
var outVariable = new Variable<string>("out", "test");
|
||||
|
||||
var subWorkflow = new AddTextSubWorkflow()
|
||||
{
|
||||
A = new("obi wan"),
|
||||
B = new (outVariable)
|
||||
};
|
||||
|
||||
workflow.Variables.Add(outVariable);
|
||||
|
||||
workflow.Root = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
subWorkflow,
|
||||
new WriteLine(context => outVariable.Get(context))
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Testing.Shared;
|
||||
using Elsa.Workflows.Core.Contracts;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Elsa.IntegrationTests.Scenarios.SetGetVariables;
|
||||
|
||||
public class Tests
|
||||
{
|
||||
private readonly IWorkflowRunner _workflowRunner;
|
||||
private readonly CapturingTextWriter _capturingTextWriter = new();
|
||||
private readonly IWorkflowBuilderFactory _workflowBuilderFactory;
|
||||
|
||||
public Tests(ITestOutputHelper testOutputHelper)
|
||||
{
|
||||
var services = new TestApplicationBuilder(testOutputHelper).WithCapturingTextWriter(_capturingTextWriter).Build();
|
||||
_workflowBuilderFactory = services.GetRequiredService<IWorkflowBuilderFactory>();
|
||||
_workflowRunner = services.GetRequiredService<IWorkflowRunner>();
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "Subsequent activity does not get scheduled when previous activity created a bookmark")]
|
||||
public async Task Test1()
|
||||
{
|
||||
await _workflowRunner.RunAsync<SetGetVariablesWorkflow>();
|
||||
var lines = _capturingTextWriter.Lines.ToList();
|
||||
Assert.Equal(new[] { "Line 5" }, lines);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
using Elsa.Workflows.Core.Abstractions;
|
||||
using Elsa.Workflows.Core.Activities;
|
||||
using Elsa.Workflows.Core.Contracts;
|
||||
using Elsa.Workflows.Core.Models;
|
||||
|
||||
namespace Elsa.IntegrationTests.Scenarios.SetGetVariables;
|
||||
|
||||
class SetGetVariablesWorkflow : WorkflowBase
|
||||
{
|
||||
protected override void Build(IWorkflowBuilder workflow)
|
||||
{
|
||||
var variable = new Variable<string>("myvar", "test");
|
||||
|
||||
workflow.Root = new Sequence
|
||||
{
|
||||
Variables = {
|
||||
variable
|
||||
},
|
||||
|
||||
Activities =
|
||||
{
|
||||
new SetVariable<string>(variable,"Line 5"),
|
||||
new WriteLine(variable)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue