SDK: Flow Steps (Advanced)
  • 09 Jun 2021
  • 4 Minutes to read
  • Dark
    Light
  This documentation version is deprecated, please click here for the latest version.

SDK: Flow Steps (Advanced)

  • Dark
    Light

Article summary

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

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

Custom codes are located here: C:\Program Files\Decisions\Decisions ServicesManager\Instances\Control\CustomReferences
  1. Create a new Class Library project in Visual Studio. Add a reference to the DecisionsFramework.dll and 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; 
    
  2. Decorate your class with the following attributes:
    [AutoRegisterStep("Step Name", "Step Category")]
    [Writable]
    
  3. Inherit from the following Classes: BaseFlowAwareStep, ISyncStep, IDataConsumer, IDataProducer.
  4. Implement BaseFlowAwareStep, ISyncStep and IDataConsumer.
    Below is how the completed code will look.

     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

The InputData property defines the input data for the step. The 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. Below 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 the OutcomeScenarios property

The OutcomeScenarios property defines the outcome data and paths for the step. The 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. Below is an example of how to build this array for the 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, the data being exposed needs to be retrieved 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, code can be written to accomplish the desired task. The key is that whenever the method ends, the code must return a 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 the Value of Other Inputs

To hide optional inputs based on the value of a property, the class must inherit from another interface called INotifyPropertyChanged. Below is an example code snippet on ow to implement this interface.

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

When writing a property to control other inputs, use the following 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");
            }
        }



Was this article helpful?