Using of parameters in Workflow Engine .NET

Using of parameters in Workflow Engine .NET

Using of parameters in Workflow Engine .NET

photo from pexels

Introduction

When you create a Scheme, you can specify which parameters belong to it. Thus together with your processes objects are stored, which can be any .NET type which is serialized to JSON. Parameters is a very powerful feature that can help you make your Schemes and Processes more efficient. In this article we will look at the using of the parameters in application to a simplified example from real life.

The Problem

We need to create a workflow of a support request. Any user can send the support request. Initially the request goes to the first line of support. Subsequently, the request may be forwarded to one of the five support divisions. IT Department, Law Department, Accounting, Marketing Department or back to the First Line. A member of each division can mark the request as resolved or rejected. Also the request can be forwarded to any other support division. Access to commands can have only employee which is working in the division that is assigned to the request. 

It would seem that we need to create five Activities for five support divisions. And connect them with command transitions each with each. So we will obtain the change of division functionality. Also, in each activity, we need two transition to Rejected and Resolved Activities. In total we need to create an workflow scheme contains seven Activities, thirty Transitions and five Actors. It looks very difficult for this simple task. In fact, this problem is easily solved by using three Activities, three Transitions and one Actor. We just need to use Parameters.

Brief overview of Parameters

When you create a Schema, you can specify Parameters to be used by your Process. The Type of the Parameter can be any .NET type which is serializable to JSON. So you can use your own custom types for process parameters. 

Each parameter has a sign of Purpose - which determines the mission and type of storage for the Parameter. Parameters can be: System - which are using by WorkflowEngine.NET and you can only read them, Persistence - which are saved between operations in your SQL or noSQL storage, Temporary - which exists only in time of a transitional process.

Parametrs which gave the Purpose == Persistence can be initialized. You have two options to initialize them. The first is to pass them when creating a new process through the  _runtime.CreateInstance(CreateInstanceParams createInstanceParams) method. The second is to specify their Initial values in the Scheme. We will need both options in this sample.

The standard way to pass and change Parameters from outside of the Process is to use a Parameters which are binded to Commands. For commands such parameters are called Input Parameters. For Input Parameters of Commands you can specify some additional attributes which you can use to build forms based on commands. Name - you can specify a name of the Input Parameter it could be same as the Name of Parameter or another. You can use it for an localization purposes. IsRequired - you can take it into account when generating forms, also it is used in the Command validation before the execution of the Command. DefaultValue - you can specify Deafult Value for each Input Parameter, this value must be either valid JSON or will be interpreted as string. You can access this value via CommandParameter.DefaultValue property. 

Let's look at the sample. 

The Sample

First we need to create two entities. SupportRequest - is the class describes the request and for storing it.

public class SupportRequest
{
    public string Name { get; set; }

    public string Subject { get; set; }

    public DateTime Date { get; set; }
}

SupportDivision - is the enum contains the names of support divisions. FirstLine, ITDepartment, LawDepartment, Accounting and MarketingDepartment. It is maked with JsonConverterAttribute to be serialized as a string by NewtonSoft.JSON serializer.

[JsonConverter(typeof(StringEnumConverter))]
public enum SupportDivision
{
    FirstLine,
    ITDepartment,
    LawDepartment,
    Accounting,
    MarketingDepartment
}

Next, lets look ath the Scheme. As promised, it contains only three Activities and three Transitions. The whole point of its work lies in the use of parameters.

In total, the scheme uses three parameters request, division and comment.  Please note that all of them have Purpose = Persistece, thus they will be stored together with your process. Let's examine their use more detail.

request - this Parameter is of type Business.SupportRequest, it is used for storing of support request, and it is passed to a new process when it is created. Thus we don't need to create a separate table in database for storing of a process request. It turns out that an entity which using workflow is stored together with the process, this approach can be very useful. The principle of parameter transfer when you creating a new process is explained in the following code. You do not need to do anything else that the parameter would have been stored together with your process. 

var processId = Guid.NewGuid();
var name = ... //Getting a name for a support request
var subject ... //Getting a subject for a support request

var supportRequest = new SupportRequest()
{
    Date = DateTime.Now,
    Name = name,
	Subject = subject
};

var createInstanceParams = new CreateInstanceParams(SchemeCode, processId)
{
	InitialProcessParameters = new Dictionary<string, object>()
		{
			{"request", supportRequest}
		}
};

WorkflowInit.Runtime.CreateInstance(createInstanceParams);

The remaining two parameters are passed to the process through commands. Both of these parameters are required so that before executing of command the  runtime will check that these parameters are filled.

division - this Parameter is of type Business.SupportDivision, it is used to indicate the division which is processing a support request now. This parameter have the Initial value = FirstLine. Thus this parameter will be initialized as FirstLine just after new process has been created. Also the parameter is changed by the command change. The code illustrates the transmission of parameter via the command is below.

var command = ... //Getting a command from a process

SupportDivision selectedDivision = ... //Getting a support division (user input)

command.SetParameter("division", selectedDivision);

WorkflowInit.Runtime.ExecuteCommand(command,...,...);

comment - this Parameter is of type String, it is only a comment that support employee must leave to each their action. In each command in the comment parameter is specified unique Default value. The code illustrates the transmission of parameter via the command and usage of the Default value is below.

var defaultComment = (string) command.Parameters.First(p => p.ParameterName.Equals("comment")).DefaultValue;

var newComment = ... //Getting a comment

if (string.IsNullOrEmpty(newComment))
    newComment = defaultComment;

command.SetParameter("comment", newComment);

WorkflowInit.Runtime.ExecuteCommand(command,...,...);

OR

var newComment = ... //Getting a comment

if (string.IsNullOrEmpty(newComment))
    command.SetParameterToDefault("comment");
else
	command.SetParameter("comment", newComment);

WorkflowInit.Runtime.ExecuteCommand(command,...,...);

In order to limit the access to all the commands using only one rule. You can find it in Code Actions, this rule is called IsSupporter. In it we read the current value of division parameter and return a list of users from the specified support division. For simplicity, each division is associated with one user.

var division = processInstance.GetParameter<SupportDivision>("division");
var result = new List<string>();

switch (division)
{
    case SupportDivision.FirstLine:
        result.Add("user1");
        return result;
    case SupportDivision.ITDepartment:
        result.Add("user2");
        return result;
    case SupportDivision.LawDepartment:
        result.Add("user3");
        return result;
    case SupportDivision.Accounting:
        result.Add("user4");
        return result;
    case SupportDivision.MarketingDepartment:
        result.Add("user5");
        return result;
    default: 
        return result;
}

Also in the scheme there is one action that simply displays all process parameters to the console. You can find it in Code Actions, this Action is called PrintRequestInfo.

var division = processInstance.GetParameter<SupportDivision>("division");
var request = processInstance.GetParameter<SupportRequest>("request");
var comment = processInstance.GetParameter<string>("comment");
var state = processInstance.ExecutedActivityState;

Console.WriteLine ("The request from: {0}, created: {1}, subject: {2}",request.Name,request.Date,request.Subject);
if (state == "Processing")
{
    Console.WriteLine ("Now in {0}", division);
}
else if (state == "Rejected")
{
    Console.WriteLine ("Was rejected by {0}", division);
}
else if (state == "Resolved")
{
    Console.WriteLine ("Was resolved by {0}", division);
}

if (!string.IsNullOrEmpty(comment))
{
  Console.WriteLine ("The last comment was {0}", comment);
}

All the key features of the example described, let's go to the demonstration.

The Demo

An example that we use in all articles was slightly modified, in order that would be easier to pass parameters to the process. Immediately after the start, you will be prompted to enter a name and a subject to create a new support request. This request will be passed to a newly created process, as shown above.

Operation:
0 - Set current user
1 - Create new support request
2 - Execute Command
3 - Set state
4 - Change parameters manually
5 - Delete the support request
6 - Exit
The support request isn t created.
Create new support request.
Please enter your name:Evgeny
Please enter a request subject:Help me!
The request from: Evgeny, created: 13.07.2016 20:22:04, subject: Help me!
Now in FirstLine

We can see that the workflow of support request has printed its state, and the document is now in FirstLine division. Let's change the current user of the user1, which operates according to the IsSupporter Rule in FirstLine division. And then we will change the support division to ITDepartment using the change command. We will need to enter two parameters (division an comment) because the change command has two parameters.

Enter code of operation:0
Enter user s id:user1

Current user = user1.
Enter code of operation:2
Available commands:
- change (LocalizedName:change, Classifier:Direct)
- rejected (LocalizedName:rejected, Classifier:Direct)
- resolved (LocalizedName:resolved, Classifier:Direct)
Enter command:change
Please choose a division to change:
1 - FirstLine
2 - ITDepartment
3 - LawDepartment
4 - Accounting
5 - MarketingDepartment
2
Please enter a comment:
The default comment is: "The division of request has been changed"
Redirected to IT department
The request from: Evgeny, created: 13.07.2016 20:22:04, subject: Help me!
Now in ITDepartment
The last comment was "Redirected to IT department"
ExecuteCommand - OK.

We can see that the workflow of support request has printed its state, and the document is now in ITDepartment division. With the change command, we can redirect a request from division to division many times. We only need to change the user. Redirect the request to the Accounting.

Enter code of operation:0
Enter user s id:user2

Current user = user2.
Enter code of operation:2
Available commands:
- change (LocalizedName:change, Classifier:Direct)
- rejected (LocalizedName:rejected, Classifier:Direct)
- resolved (LocalizedName:resolved, Classifier:Direct)
Enter command:change
Please choose a division to change:
1 - FirstLine
2 - ITDepartment
3 - LawDepartment
4 - Accounting
5 - MarketingDepartment
4
Please enter a comment:
The default comment is: "The division of request has been changed"
Redirected to the Accounting
The request from: Evgeny, created: 13.07.2016 20:22:04, subject: Help me!
Now in Accounting
The last comment was "Redirected to the Accounting"
ExecuteCommand - OK.

Finally you can change the user to a user4 (from Accounting) and mark the request as resolved using the resolved command.

Enter code of operation:0
Enter user s id:user4

Current user = user4.
Enter code of operation:2
Available commands:
- change (LocalizedName:change, Classifier:Direct)
- rejected (LocalizedName:rejected, Classifier:Direct)
- resolved (LocalizedName:resolved, Classifier:Direct)
Enter command:resolved
Please enter a comment:
The default comment is: "This request has been resolved"
Resolved by accounting
The request from: Evgeny, created: 13.07.2016 20:22:04, subject: Help me!
Was resolved by Accounting
The last comment was "Resolved by accounting"
ExecuteCommand - OK.

Manual manipulation of the process parameters.

Very rarely we need to modify the process parameters without using of commands. Below is the code that lets you do this. The general algorithm is: get the ProcessInstance object with the loaded parameters, change them, save them.

var processId = ... //Getting a Process id
var processInstance = WorkflowInit.Runtime.GetProcessInstanceAndFillProcessParameters(processId);
var newParameterValue = ... // Getting a new value of Parameter
processInstance.SetParameter("parameter name", newParameterValue);
WorkflowInit.Runtime.PersistenceProvider.SavePersistenceParameters(processInstance);

You can test this feature using Change parameters manually operation from the test application. Let's change division and comment parameters.

Enter code of operation:4
Please choose a parameter to change:
1 - division
2 - comment
1
Current division is ITDepartment
Please choose a division to change:
1 - FirstLine
2 - ITDepartment
3 - LawDepartment
4 - Accounting
5 - MarketingDepartment
5
Division has been changed to MarketingDepartment

Enter code of operation:4
Please choose a parameter to change:
1 - division
2 - comment
2
Current comment is "Resolved in IT department"
Please enter a comment:
Parameters was changed manually
Comment has been changed to "Parameters was changed manually"

Enter code of operation:3
Available state to set:
- Processing
- Resolved
- Rejected
Enter state:Processing
The request from: Evgeny, created: 13.07.2016 20:52:51, subject: Help me!
Now in MarketingDepartment
The last comment was "Parameters was changed manually"

Thank you for the attention!

  • By Dmitry Melnikov
  • 7/6/2016
  • parameters, scheme