Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
aprilesalvatore opened this issue Jan 2, 2025 · 0 comments

Comments

@aprilesalvatore
Copy link

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:

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

public Dictionary<string, string> Options { get; set; } = new Dictionary<string, string>();

Change IDefinitionLoader adding an overload of LoadDefinition method

 WorkflowDefinition LoadDefinition(string source, Func<string, DefinitionSourceV1> deserializer, Action<ExternalMapper> externalMapper);

Last changes on DefinitionLoader

private Action<ExternalMapper> _externalMapping;

 public WorkflowDefinition LoadDefinition(string source, Func<string, DefinitionSourceV1> deserializer, Action<ExternalMapper> externalMapper)
        {
            _externalMapping = externalMapper;
         ...
       }

and from the row 107

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:

 _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 :

{
  "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)"
            }
          }
        ]
      ]
    }
  ]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant