Merge pull request #146 from Andale-biz/Feature_Reflection_Activities

This commit is contained in:
Sipke Schoorstra 2019-11-12 23:13:41 +01:00 committed by GitHub
commit 3ea596cdba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 239 additions and 0 deletions

View file

@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Attributes;
using Elsa.Results;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Activities.Reflection.Activities
{
/// <summary>
/// Execute a Method by reflection.
/// </summary>
[ActivityDefinition(
Category = "Reflection",
Description = "Execute a Method by reflection.",
RuntimeDescription = "a => !!a.state.variableName ? `Execute a Method by reflection and store the result into <strong>${ a.state.variableName }</strong>.` : 'Execute a Method by reflection.'",
Outcomes = new[] { OutcomeNames.Done }
)]
public class ExecuteMethod : Activity
{
public ExecuteMethod(IWorkflowExpressionEvaluator evaluator)
{
}
[ActivityProperty(Hint = "The variables to use as parameters, seperated by comma in order of method call.")]
public string InputVariableNames
{
get => GetState<string>(null, "InputVariableNames");
set => SetState(value, "InputVariableNames");
}
[ActivityProperty(Hint = "The name of the variable to store the returned value into.")]
public string OutputVariableName
{
get => GetState<string>(null, "OutputVariableName");
set => SetState(value, "OutputVariableName");
}
[ActivityProperty(Hint = "Assembly name (fullname or filename) to load")]
public string AssemblyName
{
get => GetState<string>(null, "AssemblyName");
set => SetState(value, "AssemblyName");
}
[ActivityProperty(Hint = "Class name to start or lookup")]
public string ClassName
{
get => GetState<string>(null, "ClassName");
set => SetState(value, "ClassName");
}
[ActivityProperty(Hint = "Class is a static class?")]
public bool IsStaticClass
{
get => GetState<bool>(null, "IsStaticClass");
set => SetState(value, "IsStaticClass");
}
[ActivityProperty(Hint = "Method name to execute")]
public string MethodName
{
get => GetState<string>(null, "MethodName");
set => SetState(value, "MethodName");
}
protected override async Task<ActivityExecutionResult> OnExecuteAsync(
WorkflowExecutionContext context,
CancellationToken cancellationToken)
{
await Task.Delay(1);
var inputValues = InputVariableNames.Split(',').Select(s => context.GetVariable(s)).ToArray();
return Execute(context, inputValues);
}
protected override ActivityExecutionResult OnResume(WorkflowExecutionContext context)
{
var inputValues = InputVariableNames.Split(',').Select(s => context.GetVariable(s)).ToArray();
return Execute(context, inputValues);
}
private ActivityExecutionResult Execute(WorkflowExecutionContext workflowContext, object[] receivedInputValues)
{
string path = Directory.EnumerateFiles(AppDomain.CurrentDomain.BaseDirectory, AssemblyName, SearchOption.AllDirectories).FirstOrDefault();
Assembly assembly = Assembly.LoadFrom(path);
object receivedOutput = null;
var classType = assembly.DefinedTypes.Where(t => t.Name == ClassName).FirstOrDefault();
if (IsStaticClass)
{
var staticMethod = classType.DeclaredMethods.Where(m => m.Name == MethodName).FirstOrDefault();
receivedOutput = staticMethod.Invoke(null, receivedInputValues);
}
else
{
var instancedClass = Activator.CreateInstance(classType);
var instanceMethod = instancedClass.GetType().GetMethod(MethodName);
receivedOutput = instanceMethod.Invoke(instancedClass, receivedInputValues);
}
workflowContext.CurrentScope.SetVariable(OutputVariableName, receivedOutput);
workflowContext.SetLastResult(receivedOutput);
return Outcome(OutcomeNames.Done);
}
}
}

View file

@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Attributes;
using Elsa.Results;
using Elsa.Services;
using Elsa.Services.Models;
namespace Elsa.Activities.Reflection.Activities
{
/// <summary>
/// Execute a Method by reflection.
/// </summary>
[ActivityDefinition(
Category = "Reflection",
Description = "Split object in multiple parts to process seperately.",
RuntimeDescription = "Split object in multiple parts to process seperately.",
Outcomes = "x => x.state.properties.map(c => c.toString())"
)]
public class SplitObject : Activity
{
public SplitObject()
{
Properties = new List<string>();
}
[ActivityProperty(Hint = "The variable with the object to split")]
public string InputVariableName
{
get => GetState<string>(null, "InputVariableName");
set => SetState(value, "InputVariableName");
}
[ActivityProperty(Hint = "A comma-separated list of possible outcomes for the split parts. These are the property names of the splitted object.")]
public IReadOnlyCollection<string> Properties
{
get => GetState<IReadOnlyCollection<string>>();
set => SetState(value);
}
protected override async Task<ActivityExecutionResult> OnExecuteAsync(
WorkflowExecutionContext context,
CancellationToken cancellationToken)
{
object splitObject = null;
if (string.IsNullOrEmpty(InputVariableName))
{
splitObject = context.GetVariable(InputVariableName);
}
if (splitObject != null)
{
foreach (var Property in Properties)
{
object PropValue = FollowPropertyPath(splitObject, Property);
context.SetVariable(Property, PropValue);
}
}
return Outcomes(Properties.ToList());
}
protected object FollowPropertyPath(object value, string path)
{
Type currentType = value.GetType();
foreach (string propertyName in path.Split('.'))
{
PropertyInfo property = currentType.GetProperty(propertyName);
value = property.GetValue(value, null);
currentType = property.PropertyType;
}
return value;
}
}
}

View file

@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<PackageVersion>1.0.0</PackageVersion>
<LangVersion>latest</LangVersion>
<Authors>Elsa Contributors</Authors>
<Description>
Elsa is a set of workflow libraries and tools that enable super-fast workflowing capabilities in any .NET Core application.
This package provides the following Reflection activities:
* ExecuteFunction
</Description>
<Copyright>2019</Copyright>
<PackageProjectUrl>https://github.com/elsa-workflows/elsa-core</PackageProjectUrl>
<RepositoryUrl>https://github.com/elsa-workflows/elsa-core</RepositoryUrl>
<RepositoryType>GitHub</RepositoryType>
<PackageTags>elsa, workflows</PackageTags>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,15 @@
using Elsa.Activities.Reflection.Activities;
using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Activities.Reflection.Extensions
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddReflectionActivities(this IServiceCollection services)
{
return services
.AddActivity<ExecuteMethod>()
.AddActivity<SplitObject>();
}
}
}