Skip to content

v1.4.0

Compare
Choose a tag to compare
@danielgerlag danielgerlag released this 03 Dec 18:01
· 658 commits to master since this release

Workflow Core 1.4.0

  • Changed MongoDB persistence provider to store custom workflow data as BsonDocument instead of serialized JSON string
  • Changed .Output builder method value expression type, so inferred generic type is not taken from value expression
  • Added a feature that enables the loading of workflow definitions from JSON files

Loading workflow definitions from JSON

Simply grab the DefinitionLoader from the IoC container and call the .LoadDefinition method

var loader = serviceProvider.GetService<IDefinitionLoader>();
loader.LoadDefinition(...);

Format of the JSON definition

Basics

The JSON format defines the steps within the workflow by referencing the fully qualified class names.

Field Description
Id Workflow Definition ID
Version Workflow Definition Version
DataType Fully qualified assembly class name of the custom data object
Steps[].Id Step ID (required unique key for each step)
Steps[].StepStepType Fully qualified assembly class name of the step
Steps[].NextStepId Step ID of the next step after this one completes
Steps[].Inputs Optional Key/value pair of step inputs
Steps[].Outputs Optional Key/value pair of step outputs
Steps[].CancelCondition Optional cancel condition
{
  "Id": "HelloWorld",
  "Version": 1,
  "Steps": [
    {
      "Id": "Hello",
      "StepType": "MyApp.HelloWorld, MyApp",
      "NextStepId": "Bye"
    },        
    {
      "Id": "Bye",
      "StepType": "MyApp.GoodbyeWorld, MyApp"
    }
  ]
}

Inputs and Outputs

Inputs and outputs can be bound to a step as a key/value pair object,

  • The Inputs collection, the key would match a property on the Step class and the value would be an expression with both the data and context parameters at your disposal.
  • The Outputs collection, the key would match a property on the Data class and the value would be an expression with both the step as a parameter at your disposal.

Full details of the capabilities of expression language can be found here

{
  "Id": "AddWorkflow",
  "Version": 1,
  "DataType": "MyApp.MyDataClass, MyApp",
  "Steps": [
    {
      "Id": "Hello",
      "StepType": "MyApp.HelloWorld, MyApp",
      "NextStepId": "Add"
    },
	{
      "Id": "Add",
      "StepType": "MyApp.AddNumbers, MyApp",
      "NextStepId": "Bye",
      "Inputs": { 
          "Value1": "data.Value1",
          "Value2": "data.Value2" 
       },
      "Outputs": { 
          "Answer": "step.Result" 
      }
    },    
    {
      "Id": "Bye",
      "StepType": "MyApp.GoodbyeWorld, MyApp"
    }
  ]
}
{
  "Id": "AddWorkflow",
  "Version": 1,
  "DataType": "MyApp.MyDataClass, MyApp",
  "Steps": [
    {
      "Id": "Hello",
      "StepType": "MyApp.HelloWorld, MyApp",
      "NextStepId": "Print"
    },
    {
      "Id": "Print",
      "StepType": "MyApp.PrintMessage, MyApp",
      "Inputs": { "Message": "\"Hi there!\"" }
    }
  ]
}

WaitFor

The .WaitFor can be implemented using 3 inputs as follows

Field Description
CancelCondition Optional expression to specify a cancel condition
Inputs.EventName Expression to specify the event name
Inputs.EventKey Expression to specify the event key
Inputs.EffectiveDate Optional expression to specify the effective date
{
    "Id": "MyWaitStep",
    "StepType": "WorkflowCore.Primitives.WaitFor, WorkflowCore",
    "NextStepId": "...",
    "CancelCondition": "...",
    "Inputs": {
        "EventName": "\"Event1\"",
        "EventKey": "\"Key1\"",
        "EffectiveDate": "DateTime.Now"
    }
}

If

The .If can be implemented as follows

{
      "Id": "MyIfStep",
      "StepType": "WorkflowCore.Primitives.If, WorkflowCore",
      "NextStepId": "...",
      "Inputs": { "Condition": "<<expression to evaluate>>" },
      "Do": [[
          {
            "Id": "do1",
            "StepType": "MyApp.DoSomething1, MyApp",
            "NextStepId": "do2"
          },
          {
            "Id": "do2",
            "StepType": "MyApp.DoSomething2, MyApp"
          }
      ]]
}

While

The .While can be implemented as follows

{
      "Id": "MyWhileStep",
      "StepType": "WorkflowCore.Primitives.While, WorkflowCore",
      "NextStepId": "...",
      "Inputs": { "Condition": "<<expression to evaluate>>" },
      "Do": [[
          {
            "Id": "do1",
            "StepType": "MyApp.DoSomething1, MyApp",
            "NextStepId": "do2"
          },
          {
            "Id": "do2",
            "StepType": "MyApp.DoSomething2, MyApp"
          }
      ]]
}

ForEach

The .ForEach can be implemented as follows

{
      "Id": "MyForEachStep",
      "StepType": "WorkflowCore.Primitives.ForEach, WorkflowCore",
      "NextStepId": "...",
      "Inputs": { "Collection": "<<expression to evaluate>>" },
      "Do": [[
          {
            "Id": "do1",
            "StepType": "MyApp.DoSomething1, MyApp",
            "NextStepId": "do2"
          },
          {
            "Id": "do2",
            "StepType": "MyApp.DoSomething2, MyApp"
          }
      ]]
}

Delay

The .Delay can be implemented as follows

{
      "Id": "MyDelayStep",
      "StepType": "WorkflowCore.Primitives.Delay, WorkflowCore",
      "NextStepId": "...",
      "Inputs": { "Period": "<<expression to evaluate>>" }
}

Parallel

The .Parallel can be implemented as follows

{
      "Id": "MyParallelStep",
      "StepType": "WorkflowCore.Primitives.Sequence, WorkflowCore",
      "NextStepId": "...",
      "Do": [
		[ /* Branch 1 */
		  {
		    "Id": "Branch1.Step1",
		    "StepType": "MyApp.DoSomething1, MyApp",
		    "NextStepId": "Branch1.Step2"
		  },
		  {
		    "Id": "Branch1.Step2",
		    "StepType": "MyApp.DoSomething2, MyApp"
		  }
		],			
		[ /* Branch 2 */
		  {
		    "Id": "Branch2.Step1",
		    "StepType": "MyApp.DoSomething1, MyApp",
		    "NextStepId": "Branch2.Step2"
		  },
		  {
		    "Id": "Branch2.Step2",
		    "StepType": "MyApp.DoSomething2, MyApp"
		  }
		]
	  ]
}

Schedule

The .Schedule can be implemented as follows

{
      "Id": "MyScheduleStep",
      "StepType": "WorkflowCore.Primitives.Schedule, WorkflowCore",
      "Inputs": { "Interval": "<<expression to evaluate>>" },
      "Do": [[
          {
            "Id": "do1",
            "StepType": "MyApp.DoSomething1, MyApp",
            "NextStepId": "do2"
          },
          {
            "Id": "do2",
            "StepType": "MyApp.DoSomething2, MyApp"
          }
      ]]
}

Recur

The .Recur can be implemented as follows

{
      "Id": "MyScheduleStep",
      "StepType": "WorkflowCore.Primitives.Recur, WorkflowCore",
      "Inputs": { 
        "Interval": "<<expression to evaluate>>",
        "StopCondition": "<<expression to evaluate>>" 
      },
      "Do": [[
          {
            "Id": "do1",
            "StepType": "MyApp.DoSomething1, MyApp",
            "NextStepId": "do2"
          },
          {
            "Id": "do2",
            "StepType": "MyApp.DoSomething2, MyApp"
          }
      ]]
}