Home .NET Sequential processes in the Workflow Foundation

Sequential processes in the Workflow Foundation

by admin

Sequential processes in the Workflow Foundation
Hi everyone, today we’re finally going to getto the practical part of our Workflow Foundation mini-program.In this article, I’m going to elaborate a bit more on Sequential Workflowand describe an example of creating a file backup application. Let me remind you that this is more of an example of a workflow editor than a description of a real-world application. Everything described in the worked example can and should be done without using WF. =)

Task

Today our task is to make a program that copies newand changed files fromthe source folder to the destination folder. This is what a flowchart of the application under development will look like :
Sequential processes in the Workflow Foundation
There is nothing complicated about this program and you can implement it with a dozen lines of C#:

if ( Directory Exists( from ))<br>{<br> if (! Directory Exists(to))<br> Directory CreateDirectory(to);<br> <br> new DirectoryInfo( from ).GetFiles().Where(<br> f => <br> ! File Exists(to + f.Name) ||<br> f.LastWriteTime > new FileInfo(to + f.Name).LastWriteTime).ToList().<br> ForEach(file => File Copy( from +file.Name, to + file.Name, true ));<br> } <br> <br> * This source code was highlighted with Source Code Highlighter

But our task is not to rewrite the files, but to learn the basics of WF. Let’s take a look at the basic elements (activities) we will need.

Code Activity

Sequential processes in the Workflow Foundation
CodeActivity Allows any code to be executed. It can be a log entry or a database call. The red exclamation mark in the WF designer means that there are mandatory element properties that are left undefined. In the case of CodeActivity this warning message appeared because of the missing handler ExecuteCode which is actually a method that executes user code.

IfElseActivity

Sequential processes in the Workflow Foundation
As you can guess from the name and the image IfElseActivity is a condition checker block. It can consist of one or more branches, each of which executes nested code when a given condition is met. You can add branches by selecting Add Branch in the context menu. The last branch may have no condition and will be executed if no other conditions are met. The exclamation mark in this case means there is no condition. A condition can be a logical expression, defined in the designer, or a method, taking (objectsender, ConditionalEventArgse) You can change the type of the condition in the branch parameters :
Sequential processes in the Workflow Foundation
When selecting Declarative Rule Condition it is also necessary to specify the name of the specified rule. It can then be used in other check blocks.

While Activity

Sequential processes in the Workflow Foundation
An equally eloquent name allows us to determine that this unit performs the functions of the design while In the same way as in the branches IfElse , a condition must be setin the designer or code to make the exclamation pointdisappear. Only one element can be placed inside a block. Therefore, it is often necessary to put Sequence Activity

Sequence Activity

Sequential processes in the Workflow Foundation
The element Sequence Activity can contain any other elements. We need it in the loop while , which allows us to add only one element to itself.

Example

Let’s go straight to the example. We will have two projects. One project will be a library with processes and the other will be a console application that will use this library.

Library creation

Let’s start by creating a new blank Workflow Project :
Sequential processes in the Workflow Foundation
And add a new one to it Sequential Workflow named SyncWorkflow :
Sequential processes in the Workflow Foundation
This should open up a designer prompting us to drag and drop Activity to create a sequential process :
Sequential processes in the Workflow Foundation
And we’ll take advantage of that suggestion right away by putting the ifElse Activity there. Use the Properties panel to give the ifElse element the name checkDirectory, and its branches ifSourceDirectoryExistsand ifSourceDirectoryNotExists respectively. As a result, checkDirectoryshould look like this :
Sequential processes in the Workflow Foundation
Now we need to check if the source directory exists. To do that, we need a variable storing the path to the source directory and another one for the destination directory. To do this, let’s go to the code editor by pressing F7 in the designer or by selecting View Code from the file’s context menu. Right after the constructor, let’s create two properties :

//path to source folder <br> public string From { get ; set ; }<br> //path to destination folder <br> public string To { get ; set ; } <br> <br> * This source code was highlighted with Source Code Highlighter

Now we can move on to checking for the existence of the source folder. Go back to the designer’s window and select the ifSourceDirectoryExistsbranch, which should have an exclamation mark lit. For the Condition value in the Properties window, select Declarative Rule Condition and click on the plus sign that appears.
Sequential processes in the Workflow Foundation
Let’s set ConditionName to directoryExists and click the ellipsis button in the Expression field. This will open an editor in which you must enter a logical expression to check if the source folder exists :
Sequential processes in the Workflow Foundation
After pressing the button OK exclamation mark in the item ifSourceDirectoryExists should disappear.
Now let’s drag and drop Code Activity to the branch ifSourceDirectoryExists and let’s name it LoadDirectoryInfo A double click will take us to the automatically generated method which will be called when it is time to execute this element. In this method we will prepare the information necessary to rewrite the files. To do this, we will need some additional fields. Here is what the modified code looks like :

private int currentFileIndex;<br> private int fileCount;<br> private FileInfo[] files;<br> <br> private void LoadDirectoryInfo_ExecuteCode( object sender, EventArgs e)<br> {<br> //intialize whilecycle <br> currentFileIndex = 0;<br> files = new DirectoryInfo(From).GetFiles();<br> fileCount = files.Count();<br> <br> //create the backup folder if not exists <br> Directory CreateDirectory(To);<br> } <br> <br> * This source code was highlighted with Source Code Highlighter

We have defined the initial variables for the loop while Now it’s time to add the loop itself. To do this, we drag While Activity into the first branch of the loop and call it whileHaveFiles :
Sequential processes in the Workflow Foundation
For the sake of variety, let’s create a loop condition in the code. To do this, let’s put the following method into the editor :

private void CheckFileIndex( object sender, ConditionalEventArgs e)<br> {<br> e.Result = currentFileIndex < fileCount;<br> } <br> <br> * This source code was highlighted with Source Code Highlighter

In the designer we set the value Conditio n equal to Code Condition and in the dropdown list select the method just created :
Sequential processes in the Workflow Foundation
In order for the loop not to be eternal we need another Code Activity.But if we add it to the block immediately while , then, as we mentioned earlier, we won’t be able to add any more elements there.Todo this, we first drag Sequence Activity and we name it copyFile And then we create in it Code Activity named IncrementFileIndex with the following code :

private void IncrementFileIndex_ExecuteCode( object sender, EventArgs e)<br> {<br>currentFileIndex++;<br> } <br> <br> * This source code was highlighted with Source Code Highlighter

It’s just a matter of rewriting the necessary files. Before IncrementFileIndex let’s create ifElseBlock with one branch and name them checkFile and ifNeedCopy respectively :
Sequential processes in the Workflow Foundation
Let’s add the following checking method :

private void CheckDestinationFile( object sender, ConditionalEventArgse)<br> {<br> var destinationFileName = To + files[ currentFileIndex ].Name;<br> //check if file not exists <br> e.Result = ! File Exists(destinationFileName) ||<br> //or modified <br> new FileInfo(destinationFileName).LastWriteTime <<br> files[ currentFileIndex ].LastWriteTime;<br> } <br> <br> * This source code was highlighted with Source Code Highlighter

And also the element that copies the file :

private void Copy_ExecuteCode( object sender, EventArgs e)<br> {<br> File Copy(files[currentFileIndex].FullName, <br> To + files[currentFileIndex].Name, <br> true );<br> } <br> <br> * This source code was highlighted with Source Code Highlighter

The final touch will be a message to the console about the undiscovered source folder. We should end up with the following scheme :
Sequential processes in the Workflow Foundation

Creating a console application

The second step is to integrate our process into the application. Let’s add a console application project :
Sequential processes in the Workflow Foundation
You need to add a link to the project WorkflowProject :
Sequential processes in the Workflow Foundation
And also links to the three libraries needed to run the workflows :

  • System.Workflow.Activities
  • System.Workflow.ComponentModel
  • System.Workflow.Runtime

Sequential processes in the Workflow Foundation
Now let’s open the file Program.cs and change the method Main as follows :

private static void Main( string [] args)<br> {<br> using ( var workflowRuntime= new WorkflowRuntime())<br> {<br> //AutoResetEvent for thread synchronization <br> var waitHandle = new AutoResetEvent( false );<br> <br> //join when completed <br> workflowRuntime.WorkflowCompleted +=<br> ((sender, e) => waitHandle.Set());<br> //join when termination occurs <br> workflowRuntime.WorkflowTerminated +=<br> delegate ( object sender, WorkflowTerminatedEventArgs e)<br> {<br> Console WriteLine(e.Exception.Message);<br> waitHandle.Set();<br> };<br> <br> //parameter for the workflow <br> var parameters = new Dictionary< string , object > <br> {{ "From" , @"C:\test\"}, {" To ", @" C:\backup\"}};<br> <br> //create workflow instance and parameters to it <br> var instance =<br> workflowRuntime.CreateWorkflow( typeof (WorkflowProject.SyncWorkflow), <br> parameters);<br> <br> //start forkflow <br> instance.Start();<br> <br> //wait workflow for finish <br> waitHandle.WaitOne();<br> }<br> } <br> <br> * This source code was highlighted with Source Code Highlighter

First, an AutoResetEvent objectis created to synchronize the workflow with the main program. This occurs when calling waitHandle.Set() in the process termination event. I want to note that these events occur when any process in workflowRuntime Therefore, it is necessary to check which process the event belongs to.
Parameters are passed through the dictionary <string, object> , in which the keys match the names of the publicly available object properties. If no such property exists, an exception will be generated.
A working instance of the process is created by the method CreateWorkflow which takes as its arguments the process type and its parameters. After that, it is started with the Start
I suggest using command line arguments to pass parameters to get the finished program :

var parameters = new Dictionary< string , object > <br> {{ "From" , args[0]}, { "To" , args[1]}}; <br> <br> * This source code was highlighted with Source Code Highlighter

Now you can run the utility from the command line, specifying the source folder and the destination folder.

Conclusion

In this article we have learned the basic technical principles for constructing sequential processes and processes in WF in principle. In the next article we will create a finite state machine workflow which will use the result of today’s work as a building block.

Project source files

HabrWorkflowProject.zip

Required Components

To work with WF it is necessary to have net Framework 3 or higher. You will also need Visual Studio 2008 or Visual Studio 2005 with the WF extensions

You may also like