danielgerlag / danielgerlag/workflow-core
Change WorkflowCore.DSL to support External Mapper (for example User Task)
- Dominant language
- C#
- Stars
- 5.9k
- Forks
- 1.3k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 5
Description
Hi,
I change the DSL to support a UserTask (package WorkflowCore.Users) on my solution and I wish to share with you my solution. With there changes you will be able to implement a workflow definition using json or yaml
First of all adding this class:
``` csharp
using System;
using System.Collections.Generic;
using System.Text;
using WorkflowCore.Models;
using WorkflowCore.Models.DefinitionStorage.v1;
namespace WorkflowCore.DSL.Models
{
public class ExternalMapper
{
public StepSourceV1 Source { get; set; }
public Type DataType { get; set; }
public Type StepType { get; set; }
public WorkflowStep Step { get; set; }
}
}
```
Then change the object StepSourceV1 adding Option property
``` csharp
public Dictionary Options { get; set; } = new Dictionary();
```
Change IDefinitionLoader adding an overload of LoadDefinition method
``` csharp
WorkflowDefinition LoadDefinition(string source, Func deserializer, Action externalMapper);
```
Last changes on DefinitionLoader
``` csharp
private Action _externalMapping;
public WorkflowDefinition LoadDefinition(string source, Func deserializer, Action externalMapper)
{
_externalMapping = externalMapper;
...
}
```
and from the row 107
``` csharp
targetStep.ExternalId = $"{nextStep.Id}";
targetStep.ProceedOnCancel = nextStep.ProceedOnCancel;
if (_externalMapping != null)
_externalMapping(new ExternalMapper() { DataType = dataType, Source = nextStep, Step = targetStep, StepType = stepType });
AttachInputs(nextStep, dataType, stepType, targetStep);
AttachOutputs(nextStep, dataType, stepType, targetStep);
```
How to use ?
this is an example:
``` csharp
_definitionLoader.LoadDefinition(json, Deserializers.Json, (mapper) =>
{
if (mapper.Source.Options != null && mapper.Step.GetType().ContainsProperty("Options"))
{
mapper.Step.SetProperty("Options", mapper.Source.Options);
}
});
//where ContainsProperty and SetProperty are 2 extension methods
public static bool ContainsProperty(this Type targetType, string propertyName)
{
if (targetType == null || String.IsNullOrEmpty(propertyName))
return false;
var prop = targetType.GetProperty(propertyName);
return prop != null;
}
public static void SetProperty(this WorkflowStep step, string propertyName, object obj)
{
if (step == null || String.IsNullOrEmpty(propertyName) || obj == null)
return;
var prop = step.GetType().GetProperty(propertyName);
if (prop != null)
prop.SetValue(step, obj, null);
}
```
this is a Json example :
``` json
{
"Id": "ApprovedWorkflow",
"Version": 1,
"DataType": "TestApp.Model.Release, TestApp",
"Steps": [
{
"Id": "CheckReleaseStatusEditing",
"StepType": "WorkflowCore.Primitives.If, WorkflowCore",
"Inputs": {
"Condition": "data.State.Status == ReleaseStatus.Editing"
},
"NextStepId": "CheckReleaseStatusCompleted",
"Do": [
[
{
"Id": "UserTaskCompleteRelease",
"StepType": "WorkflowCore.Users.Primitives.UserTaskStep, WorkflowCore.Users",
"NextStepId": "setCompletedOutput",
"Inputs": {
"Prompt": "\"Completare la release?\"",
"AssignedPrincipal": "data.CompletedByUser"
},
"Options": {
"Completed": "\"Completa\"",
"Cancel": "\"Annulla\""
}
},
{
"Id": "setCompletedOutput",
"StepType": "TestApp.Steps.SetOutputStep, TestApp",
"Outputs": {
"State.Status": "Utils.SetStatus(UserAction)",
"State.Name": "Utils.SetName(UserAction)"
}
}
]
]
},
{
"Id": "CheckReleaseStatusCompleted",
"StepType": "WorkflowCore.Primitives.If, WorkflowCore",
"Inputs": {
"Condition": "data.State.Status == ReleaseStatus.Completed && Utils.CompareUser(data.CompletedByUser, context)"
},
"Do": [
[
{
"Id": "UserTaskApproveRelease",
"StepType": "WorkflowCore.Users.Primitives.UserTaskStep, WorkflowCore.Users",
"NextStepId": "setApprovedOutput",
"Inputs": {
"Prompt": "\"Approvare la release?\"",
"AssignedPrincipal": "data.CompletedByUser"
},
"Options": {
"Approved": "\"Approvate\"",
"Declined": "\"Declina\"",
"Cancel": "\"Annulla\""
}
},
{
"Id": "setApprovedOutput",
"StepType": "TestApp.Steps.SetOutputStep, TestApp",
"Outputs": {
"State.Status": "Utils.SetStatus(UserAction)",
"State.Name": "Utils.SetName(UserAction)"
}
}
]
]
}
]
}
```
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by locating IDefinitionLoader, DefinitionLoader, and StepSourceV1, then inspect the existing LoadDefinition flow and how workflow steps are created. The change is complete when external mapping can receive source options and the created step, while the existing DSL loading behavior remains available through its current overload.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100