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

By submitting your information, you agree that devx.com may send you DevX offers via email, phone and text message, as well as email offers about other products and services that DevX believes may be of interest to you. DevX will process your information in accordance with the Quinstreet Privacy Policy.


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

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.




Application Security Testing: An Integral Part of DevOps

Manually Unloading and Loading the Workflow Instance
The previous example showed how a workflow runs and then is automatically persisted when it encounters the Delay activity. Besides this, you can also manually persist a workflow instance. To see how this is done, let's use a Windows application as the host in this next example.

Using Visual Studio 2005, create a new Sequential Workflow Library project and name it C:\WorkflowLibrary1.

Create the workflow in Workflow1.vb as shown in Figure 8. This is similar to the workflow created earlier, without the delayActivity activity.

In the code-behind 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) System.Threading.Thread.Sleep(5000) End Sub Private Sub Code2( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) Console.WriteLine("In CodeActivity2: " & Now.ToString) End Sub

Note that I have inserted a Thread.Sleep() statement to simulate the activity taking a long time to process. In this case, the delay is five seconds.

Build the WorkflowLibrary1 project by right-clicking on its project name in Solution Explorer and then select Build.

Add a new Windows application project to the current solution. Name it C:\PersistenceWorkflowWindow. Add the System.Workflow.Runtime assembly to the project (right-click on project name and select Add Reference…). Also add the WorkflowLibrary1.dll that you just built to the project.

Add three Button controls to the default Form1 (see Figure 9). The three buttons are to start a workflow, unload a workflow from memory, and to load a workflow into memory.

Figure 8. This second workflow is the same as the earlier one without the Delay activity.
Figure 9. Populate the default Form1 with three Button controls.

Switch to the code-behind of Form1 and import the following namespace:

Imports System.Workflow.Runtime Imports System.Workflow.Runtime.Hosting Imports System.Threading

Declare the following member variables:

Public Class Form1 Private WaitHandle As AutoResetEvent Private workflowRuntime As New WorkflowRuntime() Private workflowInstance As WorkflowInstance

In the Load event of the form, add the various event handlers to the WorkflowRuntime object and add the SqlPersistenceService service to it:

Private Sub Form1_Load( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load WaitHandle = New AutoResetEvent(False) '---monitor workflow events--- AddHandler workflowRuntime.WorkflowCompleted, _ AddressOf OnWorkflowCompleted AddHandler workflowRuntime.WorkflowTerminated, _ AddressOf OnWorkflowTerminated AddHandler workflowRuntime.WorkflowUnloaded, _ AddressOf OnWorkflowUnloaded AddHandler workflowRuntime.WorkflowPersisted, _ AddressOf OnWorkflowPersisted AddHandler workflowRuntime.WorkflowIdled, _ AddressOf OnWorkflowIdled AddHandler workflowRuntime.WorkflowLoaded, _ AddressOf OnWorkflowLoaded workflowRuntime.AddService(( _ New SqlWorkflowPersistenceService( _ "Initial Catalog=SqlPersistenceService;" & _ "Data Source=.\SQLEXPRESS;Integrated" & _ " Security=SSPI;"))) End Sub

Define the event handlers as you did previously:

Private Sub OnWorkflowCompleted( _ ByVal sender As Object, _ ByVal e As WorkflowCompletedEventArgs) Console.WriteLine("Workflow completed.") WaitHandle.Set() End Sub Private Sub OnWorkflowTerminated( _ ByVal sender As Object, _ ByVal e As WorkflowTerminatedEventArgs) Console.WriteLine("Workflow terminated.") Console.WriteLine(e.Exception.Message) WaitHandle.Set() End Sub Private Sub OnWorkflowUnloaded( _ ByVal sender As Object, _ ByVal e As WorkflowEventArgs) Console.WriteLine("Workflow unloaded.") End Sub Private Sub OnWorkflowPersisted( _ ByVal sender As Object, _ ByVal e As WorkflowEventArgs) Console.WriteLine("Workflow persisted.") End Sub Private Sub OnWorkflowIdled( _ ByVal sender As Object, _ ByVal e As WorkflowEventArgs) Console.WriteLine("Workflow idle.") ThreadPool.QueueUserWorkItem( _ New WaitCallback(AddressOf UnloadInstance), _ e.WorkflowInstance) End Sub Private Sub UnloadInstance( _ ByVal workflowInstance As Object) CType(workflowInstance, WorkflowInstance).TryUnload() End Sub Private Sub OnWorkflowLoaded( _ ByVal sender As Object, _ ByVal e As WorkflowEventArgs) Console.WriteLine("Workflow loaded.") End Sub

In the Click event of the Start button, create a new thread that invokes the StartWorkflow() subroutine, which will be defined next:

Private Sub btnStart_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnStart.Click Dim t1 As New Thread(AddressOf StartWorkflow) t1.Start() End Sub

The StartWorkflow() subroutine creates a new workflow instance and starts it. You must start it on a separate thread because once the workflow instance is started, the user interface of the Windows application will be frozen and it will then be impossible to click on the Unload button to unload the workflow.

Private Sub StartWorkflow() workflowInstance = _ workflowRuntime.CreateWorkflow( _ GetType(WorkflowLibrary1.Workflow1)) workflowInstance.Start() '---wait for the event to be signaled--- WaitHandle.WaitOne() End Sub

To manually unload an executing workflow instance, use the Unload() method, as shown here in the Click event of the Unload button:

Private Sub btnUnload_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnUnload.Click Try workflowInstance.Unload() Catch ex As Exception MsgBox(ex.ToString) End Try End Sub

Once a workflow instance is unloaded, it will be persisted to the SQL database. To load the workflow instance, code the Click event of the Load button and use the Load() method:

Private Sub btnLoad_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnLoad.Click Try workflowInstance.Load() Catch ex As Exception MsgBox(ex.ToString) End Try End Sub

You are now ready to test the application. Set the Windows application as the startup project and press F5. To view the messages printed by the Console.WriteLine() statements, select View—>Output in Visual Studio 2005.

Figure 10 shows what happened when I allowed the workflow to run from beginning to end. In this example, I clicked on the Start button and let the workflow execute till its conclusion.

Figure 10. Here I've run a workflow from beginning to end with no interruptions.
Figure 11. Here I interrupted the workflow by manually requesting to unload and load a workflow instance.

Figure 11 shows what happened when the workflow is started and then unloaded and finally loaded again. I clicked the Start button to start the workflow and, later, unload (by clicking on the Unload button) while it was still executing. Finally, I clicked the Load button to load the workflow instance from the SQL database.

In this article, you have seen how long-running workflows can be persisted to external media such as a SQL Server database. You have also seen how to manually unload a workflow instance from memory. Persisting workflows is important as it conserves valuable memory and allows you to execute long-running workflows without worrying about resource constraints.

Wei-Meng Lee is a Microsoft MVP and founder of Developer Learning Solutions, a technology company specializing in hands-on training on the latest Microsoft technologies. He is an established developer and trainer specializing in .NET and wireless technologies. Wei-Meng speaks regularly at international conferences and has authored and coauthored numerous books on .NET, XML, and wireless technologies. He writes extensively on topics ranging from .NET to Mac OS X. He is also the author of the .NET Compact Framework Pocket Guide, ASP.NET 2.0: A Developer's Notebook (both from O'Reilly Media, Inc.), and Programming Sudoku (Apress). Here is Wei-Meng's blog.
Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



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