WF 4.0 WorkflowServiceHost Persistence – Part 1

First step is setting up the new persistence databases. Go to “C:\Windows\Microsoft.NET\Framework\v4.0.30319\SQL\en” and there you will find two files:
– SqlWorkflowInstanceStoreSchema.sql
– SqlWorkflowInstanceStoreLogic.sql

In SQL Server (Express or above), create a database with a convenient name (my database is called “SqlWorkflowInstanceStore”) and run the above scripts to create the required objects.

The persistence model in WF 4 is different than that of WF 3.5. the new model is now called InstanceStore instead of PersistenceProvider. For WF 3.5, the PersistenceProvider databases are still available in the same location:
– SqlPersistenceProviderLogic.sql
– SqlPersistenceProviderSchema.sql

In WF 3.5 there was service for managing WFs such as waking up workflow instances… the SQL files for this service is also still available in the same location:
– SqlPersistenceService_Logic.sql
– SqlPersistenceService_Schema.sql

For tracking in 4.0 there is no tracking participant that writes to a SQL. The Tracking_Schema.sql applies to 3.5 WFs. Out of the box with WF 4.0 there is a tracking participant that writes to ETW (Event Tracing for Windows). Again, those files for WF 3.5 are:
– Tracking_Schema.sql
– Tracking_Logic.sql

Building the WF

Create a new Console Workflow Application, and use the default Workflow1.xaml to build the following simple workflow:

The Receive and SendReplyToReceive shape receives an empty request and returns the workflow instance id to the caller. The CodeAcitivty1 is a custom activity that retrieves the workflow instance id. Below is the code for this activity:

public sealed class CodeActivity1 : CodeActivity
{protected override Guid Execute(CodeActivityContext context)
{
return context.WorkflowInstanceId;
}
}

The important catch is to set the property PersistBeforeSend on the SendReplyToReceive shape. This will cause the WF to persist just before sending the response to the caller. This means that now the WF will have a point to go back to in case the WF is suspended or unloaded…more on that later.

The Delay activity is used to delay the WF for 1 minute…we will see why is that required after moments.

Now go to the Program.cs file and let’s write the code required to host the WF and set up persistence.

Use the following code and then I will explain it:

class Program
{
static void Main(string[] args)
{
//WorkflowInvoker.Invoke(new Workflow1());string baseAddress = “http://localhost:8089/TestWF”;using (WorkflowServiceHost host =
new WorkflowServiceHost(new Workflow1(), new Uri(baseAddress)))
{
host.Description.Behaviors.Add(new
ServiceMetadataBehavior() { HttpGetEnabled = true });

host.AddServiceEndpoint(“IService”,new BasicHttpBinding(), baseAddress);

SqlWorkflowInstanceStore instanceStore = new SqlWorkflowInstanceStore(@”Data Source=.\SQLServer2008;Initial Catalog=SqlWorkflowInstanceStore;Integrated Security=True”);
host.DurableInstancingOptions.InstanceStore = instanceStore;

host.Open();
Console.WriteLine(“Car rental service listening at: ” +
baseAddress);
Console.WriteLine(“Press ENTER to exit”);
Console.ReadLine();
}

}
}

By default, the WorkflowInvoker is used to invoke the WF. I changed this into the WorkflowServiceHost, the reason is that the WorkflowInvoker cannot be configured with Persistence. WorkflowServiceHost is used to host WF Services. The other method of calling (hosting) workflows is the WorkflowApplication which – like WorkflowServiceHost – can be used to host long running asynch workflows with extensions (Persistence, Tracking) however only for workflows that are non services.

After creating my WCF endpoint and adding it to the host, I use the SqlWorkflowInstaceStore class to configure my persistence store, which is the same store I prepared when I first started.

Creating the Client

Run the WF so that the host is running and the WCF endpoint is listening for requests on “http://localhost:8089/TestWF”
Now create a client (console) application and add a service reference to the above URL. Write the following code to invoke the service operation:

ServiceReference1.ServiceClient proxy = new ServiceReference1.ServiceClient();Guid workflowId = (Guid)proxy.Operation1();

Console.WriteLine(“client done”);
Console.WriteLine(“enter key”);
Console.ReadLine();

Run the client and observe the scenario: once the operation is invoked (and the workflow instance id is returned), open the table “InstancesTable” and you will see a record for a persisted WF. Why is that? Recall that we set a property on the SendReply shape to persist just before sending the reply. For this the WF has persisted state in the database but is still running as we did not suspend or unload the WF. See images below:


For how much time will this record appear in the database? For 1 minute because we have a delay shape in the WF to delay completion for 1 minute after which the WF execution will complete and the record will disappear from the database.

In part 2 I will add support (behavior) to persist and unload the WF as well as add control endpoint to execute remote operations on the WF.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s