danielgerlag / danielgerlag/workflow-core

Change WorkflowCore.DSL to support External Mapper (for example User Task)

Open
#1,326 0 comments 0 reactions 0 assignees View on GitHub
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.