RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Execute a Long-Running Workflow Using Persistence in Windows WF : Page 2

If you're experimenting with workflows it won't be long before you find that you need to run a workflow that is too long to execute directly from memory. A workflow that needs hours—or even days—to conclude requires you to persist the workflow instance to an external medium so that the workflow can be continued later.

Creating the Sample Application
With the database prepared, let’s now build a very simple workflow application to see how a workflow instance can be persisted.

Using Visual Studio 2005, create a new Sequential Workflow Console Application and name it C:\PersistenceWorkflow.

In the Design View of WorkFlow1.vb, drag-and-drop the following Workflow activities (see also Figure 6):

  • Code
  • Delay

Set the properties of the activities as shown in Table 1.

Table 1. Workflow Activities and their Corresponding Properties.

Activity Property Value
codeActivity1 ExecuteCode Code1
delayActivity1 TimeoutDuration 00:00:05
codeActivity2 ExecuteCode Code2

In the Code View of Workflow1.vb, code the following:

    Private Sub Code1( _
       ByVal sender As System.Object, _
       ByVal e As System.EventArgs)
        Console.WriteLine("In CodeActivity1: " & Now.ToString)
    End Sub

    Private Sub Code2( _
       ByVal sender As System.Object, _
       ByVal e As System.EventArgs)
        Console.WriteLine("In CodeActivity2: " & Now.ToString)
    End Sub
In Module1.vb, there is already some code written for you to host the workflow. Add to it the following code shown in bold typeface:

        Shared Sub Main()
            Using workflowRuntime As New WorkflowRuntime()
                AddHandler workflowRuntime.WorkflowCompleted, _
                   AddressOf OnWorkflowCompleted
                AddHandler workflowRuntime.WorkflowTerminated, _
                   AddressOf OnWorkflowTerminated

                AddHandler workflowRuntime.WorkflowIdled, _
                   AddressOf OnWorkflowIdled
                AddHandler workflowRuntime.WorkflowPersisted, _
                   AddressOf OnWorkflowPersisted
                AddHandler workflowRuntime.WorkflowUnloaded, _
                   AddressOf OnWorkflowUnloaded
                AddHandler workflowRuntime.WorkflowLoaded, _
                   AddressOf OnWorkflowLoaded

                workflowRuntime.AddService( _
                   New SqlWorkflowPersistenceService( _
                   "Initial Catalog=SqlPersistenceService;" & _
                   "Data Source=.\SQLEXPRESS;Integrated " & _

                Dim workflowInstance As WorkflowInstance
                workflowInstance = _

            End Using
        End Sub
Essentially, you are adding the other event handlers for the workflow so that you'll be able to tell when the workflow is idled, persisted, loaded, and unloaded. In addition, this code adds a new SqlWorkflowPersistenceService service to the workflow. This will allow an instance of your workflow to be persisted to a SQL database when persistence should occur. The connection string to the database is passed as a parameter to this service.

Figure 6. Workflow: Design the workflow with two activities: code and delay.
Figure 7. You can learn a lot about what series of events occurred when the application runs by observing the messages printed when the workflow executes.

I also added a Console.ReadLine() statement so that the console window will not be closed immediately after the workflow finishes execution. This will allow you to observe the values printed on the screen.

In the OnWorkflowCompleted and OnWorkflowTerminated event handlers, add the two WriteLine() statements as shown in bold typeface below:

        Shared Sub OnWorkflowCompleted( _
           ByVal sender As Object, _
           ByVal e As WorkflowCompletedEventArgs)
            Console.WriteLine("Workflow completed.")
        End Sub

        Shared Sub OnWorkflowTerminated( _
           ByVal sender As Object, _
           ByVal e As WorkflowTerminatedEventArgs)
            Console.WriteLine("Workflow terminated.")
        End Sub
Add the following event handlers:

        Shared Sub OnWorkflowIdled( _
           ByVal sender As Object, _
           ByVal e As WorkflowEventArgs)
            Console.WriteLine("Workflow idle.")
            ThreadPool.QueueUserWorkItem( _
               New WaitCallback(AddressOf UnloadInstance), _
        End Sub
The OnWorkflowIdled event is invoked when a workflow goes into an idle state, such as when executing the Delay activity. For thread safety, you need to queue the events raised back from a workflow on the ThreadPool class.

The next event handler is the OnWorkFlowPersisted event:

        Shared Sub OnWorkflowPersisted( _
           ByVal sender As Object, _
           ByVal e As WorkflowEventArgs)
            Console.WriteLine("Workflow persisted.")
        End Sub
This event handler is invoked when the workflow is persisted. It implicitly calls the SaveWorkflowInstanceState method of the SqlPersistenceService class to save the workflow instance.

Once the workflow instance is persisted, the OnWorkflowUnloaded event is fired:

        Shared Sub OnWorkflowUnloaded( _
           ByVal sender As Object, _
           ByVal e As WorkflowEventArgs)
            Console.WriteLine("Workflow unloaded.")
        End Sub
This event is invoked when the workflow is unloaded from memory. This is performed by the UnloadInstance() method, which was referenced earlier in the OnWorkflowIdled event. The main purpose of the UnloadInstance() method is to perform the unloading of workflow instance.

        Shared Sub UnloadInstance( _
           ByVal workflowInstance As Object)
            CType(workflowInstance, WorkflowInstance).TryUnload()
        End Sub
When a workflow instance is to be resumed, it must be loaded back into memory. This is performed by the OnWorkflowLoaded event. It implicitly calls the LoadWorkflowInstanceState method of the SqlPersistenceService class to load the saved workflow instance into memory:

        Shared Sub OnWorkflowLoaded( _
           ByVal sender As Object, _
           ByVal e As WorkflowEventArgs)
            Console.WriteLine("Workflow loaded.")
        End Sub
Press F5 to test the application. Figure 7 shows the output observed. Notice that there is a delay of five seconds between the first and second Code activities. Also note the series of events that were fired when the workflow instance was persisted to the SQL database and then loaded back into memory.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date