SDK: Flow Steps (Advanced)
  • 15 Apr 2024
  • 4 Minutes to read
  • Dark
    Light

SDK: Flow Steps (Advanced)

  • Dark
    Light

Article Summary

Version 7.x .NET Architecture Change

Overview

While creating simple steps using the Public Static method is easier, developers may want to write a full Decisions step to do complex things. This may include having multiple outcome paths or validate input data at design time (e.g. ensure that the value of one input property is set if the value of another property = X).

Creating advanced Flow Steps will allow developers to control:

  • Variable inputs or outputs.
  • Need advanced configuration.
  • Need for custom validation.
  • Hiding and showing properties.
  • A better user experience when editing.

ISyncStep

  • Design Time: Outcomes (Step paths to be connected to other steps).
  • Run Time: Run behavior.
  • Complete and immediately return an example, don’t have to keep the history (run and throw away).

IAsyncStep

  • Design Time: Outcomes (Step paths to be connected to other steps).
  • Run Time: Step starts and returns nothing, flowTrackingId and stepTrackingId used to resume later.
Decisions has a Public GitHub Repository with various SDK examples available.

Example: Creating ISync Step

In this example, create a step that evaluates if two numbers divide evenly. This step will result in one of three paths, Yes, No and Error.

Custom codes are located here: C:\Program Files\Decisions\Decisions Server\Instances\Control\CustomReferences

Create a new Class Library(.NET Core) Project. Add a reference to the DecisionsFramework dll located in C:\Program Files\Decisions\Decisions Server\bin\DecisionsFramework.dll. Add the following using statements.

using DecisionsFramework.Design.Flow;
using DecisionsFramework.Design.Flow.Mapping;
using DecisionsFramework.Design.Flow.CoreSteps;
using DecisionsFramework.Design.ConfigurationStorage.Attributes;
using System.Collections.Generic; 

Decorate the class with the following attributes.

[AutoRegisterStep("Step Name", "Step Category")]
[Writable]

Inherit from the following Classes: BaseFlowAwareStep, ISyncStep, IDataConsumer, IDataProducer.

Implement BaseFlowAwareStep, ISyncStep and IDataConsumer.

The code should look like this:

using System;
using DecisionsFramework.Design.Flow;
using DecisionsFramework.Design.Flow.Mapping;
using DecisionsFramework.Design.Flow.CoreSteps;
using DecisionsFramework.Design.ConfigurationStorage.Attributes;
using System.Collections.Generic;
 
namespace SampleDecisionsStep
{
    [AutoRegisterStep("Do Numbers Divide Evenly", "Math")]
    [Writable]
    public class MyClass : BaseFlowAwareStep, ISyncStep, IDataConsumer, IDataProducer 
    {
        public override OutcomeScenarioData[] OutcomeScenarios
        {
            get { throw new NotImplementedException(); }
        }
 
        public ResultData Run(StepStartData data)
        {
            throw new NotImplementedException();
        }
 
        public DataDescription[] InputData
        {
            get { throw new NotImplementedException(); }
        }
    }
}

How to build out InputData property

This property defines the input data for the step. Our step needs to have two pieces of input data: a divisor and a dividend.

The InputData property also needs to return a DataDescription[] in its get accessor. Each item in the DataDescription[] describes one piece of input data. Here is an example of how to build this array for the step. The code below describes two pieces of input data. Both are Integers. The words "Dividend" and "Divisor" will be displayed in the designer when a user edits the properties of this step.

 return new DataDescription[] { new DataDescription(new DecisionsNativeType(typeof(int)), "Dividend"),
                    new DataDescription(new DecisionsNativeType(typeof(int)), "Divisor")};

How to build out OutcomeScenarios property

This property defines the outcome data and paths for the step. Our step needs three outcome paths: Yes, No and Error. Only the error path will return data (the error message).

The OutcomeScenarios property needs to return an OutcomeScenarioData[] in its get accessor. Each item in the OutcomeScenarioData[] describes one outcome path and the data it returns. Here is an example of how to build this array for our step:

 return new OutcomeScenarioData[] { 
                    new OutcomeScenarioData("Error",new DataDescription[] { new DataDescription(new DecisionsNativeType(typeof(string)), "Error Message", false, true, false)}),
                    new OutcomeScenarioData("Yes"),
                    new OutcomeScenarioData("No")};

How to build out a Run method

Since the step has input data, first get that data exposed in the run method. The input data is contained within the StepStartData of the run method and can be accessed as shown in the example below.


The values "Dividend" and "Divisor" must match the values that you entered when building the DataDescription[] within the OutcomeScenarios property.

 int dividend = (int)data.Data["Dividend"];
int divisor = (int)data.Data["Divisor"];

Now that the input data is available within the method, write whatever code is necessary to accomplish the function of the step. The key is that whenever the method ends, it must return ResultData. Here are two examples, one showing how to build this result data on a path that doesn't return data and one that does return data.


In the below example the "Error Message" and "Error" must match exactly what was used when writing the OutcomeScenarios property.

 //Example of returning a path without data
return new ResultData("Yes");
 //Example of returning a path with data
Dictionary resultData = new Dictionary();
resultData.Add("Error Message", ex.Message);
return new ResultData("Error", resultData);

Hiding Inputs Based on Value of Other Inputs

If desired users can hide optional inputs based on the value of a property. In order to do this, inherit it from another interface: INotifyPropertyChanged. How to implement this interface can be seen in the code snippet below.

 public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

When you write a property that you want to use to control other inputs, you can call the below method.

 [PropertyClassification(new string[]{"Inputs"})]
        public bool SpecifyFileExtension
        {
            get { return specifyFileExtension; }
            set
            {
                specifyFileExtension = value;
                //Call OnPropertyChanged method for each property you want to update
                this.OnPropertyChanged("SpecifyFileExtension");
                //If any of the inputs you want to update are in InputData (not a property),
                //you need to update InputData and shown below.
                this.OnPropertyChanged("InputData");
            }
        }

Getting your step into Decisions

After writing the methods, build the project, copy the compiled dll to C:\Program Files\Decisions\Decisions Server\modules\Decisions.Local\CoreServicesDlls, and restart Decisions Server service Or iisreset if IIS Hosted.

After Service Host Manager has finished restarting, log into the Decisions portal and create a new flow. You will now see the methods from your class in the Toolbox.


Was this article helpful?