Flow Steps (Advanced)
  • Updated on 11 Dec 2013
  • 4 minutes to read
  • Print
  • Dark
    Light

Flow Steps (Advanced)

  • Print
  • Dark
    Light

Summary

While creating simple steps using the Public Static method is easier, you may want to write a full Decisions step if you need to do complex things. These 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).

  • Why to create
    o Variable inputs or outputs
    o Need advanced configuration
    o Need for custom validation
    o Hiding and showing properties
    o Better user experience when editing
  • ISyncStep and IAsyncStep defined
  • Creating IAsyncStep

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

*Note custom codes are located here: C:\Program Files\Decisions\Decisions Services Manager\Instances\Control\CustomReferences

Create a new Class Library project is Visual Studio.

Add a reference to the 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 your 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

Your code should now 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 our step:

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

The code above 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.

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 a 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 Run method
Since our step has input data, we first want to 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.

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

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

Now that your input data is available within your method you can write whatever code is necessary to accomplish that you want your step to do. The key is that whenever your method ends, you 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:

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

Note: in the above example the "Error Message" and "Error" must match exactly what was used when writing the OutcomeScenarios property.

Hiding Inputs Based on Value of Other Inputs
If you would like to hide optional inputs based on the value of a property then, you need to inherit 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 this 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 you have written your methods build your project , copy the compiled dll to C:\Program Files\Decisions\Decisions Services Manager\modules\Decisions.Local\ServicesDlls , and restart Service Host Manager service .

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?