I'm Keyvan Nayyeri, a 25 years old Ph.D. student at
the Computer Science department of
the University of Texas at San Antonio.
I'm also
a Software Architect and Developer and previously held a B.Sc.
degree in Applied Mathematics.
This is my blog where I publish content about various topics specifically Programming Languages and Compilers, Software
Engineering and Programming.
If you're a big fan of sleeping like me, probably have faced with many cases that your transactions were aborted when you were asleep! For long running transactions this is a common scenario. You can't guarantee the life of a transaction. It can take one second, one minute, one hour or five years or even longer than these.
In Windows Workflow Foundation you should consider all types of transactions so you may get in trouble with a case when your transaction is running for a long time and suddenly aborts for any reason. This can happen for a site workflow which runs for several hours, days or weeks. One day server restarts everything and you'll miss your workflow state.
Thankfully Microsoft thought about these cases and a solution is included in Windows Workflow Foundation to store the state of running workflow and retrieve it later. In this post I'll talk about SqlWorkflowPersistenceService object which does this and stores/retrieves state information in/from SQL Server database.
First I start with a simple Sequential Workflow Console Application. It's not more than a simple Delay activity which forces the workflow to wait for 50 milliseconds.

InitializeTimeOutDuration event handler logic for delayActivity1 isn't more than writing a text to Console.
private void delayActivity1_InitializeTimeoutDuration(object sender, EventArgs e)
{
Console.WriteLine("Hello Gholi!");
}
Later I'll use an instance of this workflow for my examples. I could load a workflow on fly for my examples but used this approach to let you see it in designer.
In order to be able to save and retrieve the state of workflow runtime using SqlWorkflowPersistenceService, you need to configure your SQL Server database to store data. There are two SQL scripts located at C:\WINDOWS\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL\EN which are named SqlPersistenceService_Schema.sql and SqlPersistenceService_Logic.sql. First one defines the structure of database and tables and second one defines stored procedures.
Note that DTC must be started for your SQL Server in order to be able to use SqlWorkflowPersistenceService.
I create a database and run these scripts for it to get appropriate structure.
Now that I produced all prerequisites, I write a simple WinFX application which has two buttons. First one creates a workflow runtime and loads above workflow activity into memory then saves its state into database. Second button retrieves the workflow runtime state from database and follows the activity then unloads it. The XAML definition for user interface isn't necessary here but would be a simple practice for beginners:
<Window x:Class="SqlPersistenceService.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SqlPersistenceService" Height="250" Width="250"
>
<StackPanel Margin="50">
<Button Click="LoadClick" Width="100" Height="40" Background="Bisque">
Load
</Button>
<Button Click="UnLoadClick" Width="100" Height="40" Background="Chartreuse">
UnLoad
</Button>
</StackPanel>
</Window>
So my user interface is as simple as this:

In the code behind for this user interface I add some references to workflow namespaces and define an id property to keep my workflow instance identifier as well as a string property to keep my database connection string.
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;
namespace SqlPersistenceService
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : System.Windows.Window
{
private Guid id;
private string connectionString =
"Data Source=KEYVANNAYYERI;Initial Catalog=SqlPersistenceSample;Integrated Security=True";
There are two click event handlers in this code:
First one (LoadClick) creates a workflow runtime and an instance of SqlWorkflowPersistenceService by passing SQL Server connection string to its constructor. Then adds this object to workflow runtime services. After that, it loads an instance of Workflow1 into workflow runtime then this instance starts and shows its identifier in a MessageBox. This identifier is also stored in id property for later use. Finally workflow runtime stops. At this stage SqlWorkflowPersistenceService stores the state into database.
void LoadClick(object sender, RoutedEventArgs args)
{
WorkflowRuntime workflowRuntime = new WorkflowRuntime();
SqlWorkflowPersistenceService sqlPersistenceService =
new SqlWorkflowPersistenceService(this.connectionString);
workflowRuntime.AddService(sqlPersistenceService);
workflowRuntime.StartRuntime();
WorkflowInstance instance =
workflowRuntime.CreateWorkflow(typeof(SampleWorkflow.Workflow1));
this.id = instance.InstanceId;
MessageBox.Show(instance.InstanceId.ToString(), "Instance GUID");
instance.Load();
instance.Start();
workflowRuntime.StopRuntime();
}
Second click event handler (UnloadClick) loads my workflow runtime from memory again. Then gets a workflow instance of Workflow1 from this workflow runtime by passing previously saved identifier of workflow to GetWorkflow() method. Then shows the identifier of this instance in a MessageBox and finally workflow instance unloads.
Note that you'll see same GUIDs for both MessageBoxes and this means they're both running in same workflow runtime. If you pass any other id to GetWorkflow() method, it will throw an exception because can't find this instance in what is stored in database.
void UnloadClick(object sender, RoutedEventArgs args)
{
WorkflowRuntime workflowRuntime = new WorkflowRuntime();
SqlWorkflowPersistenceService sqlPersistenceService =
new SqlWorkflowPersistenceService(this.connectionString);
workflowRuntime.AddService(sqlPersistenceService);
workflowRuntime.StartRuntime();
WorkflowInstance instance =
workflowRuntime.GetWorkflow(this.id);
MessageBox.Show(instance.InstanceId.ToString(), "Instance GUID");
instance.Unload();
workflowRuntime.StopRuntime();
}
Now I check my database to see the data for my workflow runtime:

You can also configure your applications via configuration files to let them store their workflow runtime state into database.
Keyvan Nayyeri
Oct 15, 2006 9:10 AM
#
Rahul Jain
Oct 20, 2006 9:46 AM
#
Mishi
Nov 20, 2006 9:17 AM
#
Keyvan Nayyeri
Nov 20, 2006 10:44 PM
#
mausam
Dec 15, 2006 4:47 AM
#
Jose
May 28, 2007 5:45 AM
#
Greg
Jul 24, 2007 2:26 PM
#
ST
Sep 27, 2007 12:24 AM
#
Keyvan Nayyeri
Oct 22, 2007 8:41 PM
#
wf fan
Apr 22, 2008 9:49 PM
#
Hi I am very new to WF and I have gone through and read few things about which got me started. I have a situation where users wants some changes to the application we have developed.At the moment they have to fill up the change request forms, get authorisation blah blah.I was hoping that I can automate this by a workflow.Which is Ok but what I would like to know is (maybe this is a very stupid question) the info regarding what changes to be made and the requestor details should be separated in the separate database or in the sqlpersistence? any advice in the right direction would be muchly appreciated.
thanks
gayathrinatarajan
Mar 08, 2010 6:02 AM
#
Very Nice and superb article.its very helpful for me to understand the basic idea about persistence.can u give something for tracking workflow data.
thanks in advance.
Leave a Comment