Experiencing Workflow Foundation - Persistence Service and Tracking Service

Just at a new client and investigating if Workflow Foundation will suit their needs. I'm pretty new to Workflow so it's a nice learning step for me. I already stepped into the Persistence and Tracking features of Workflow Foundation.

Combining the Persistence Service and Tracking Service in one Database

It's very easy to add the Persistence Service or the Tracking Service to the WorkflowRuntime. To add the Persistence Service you can configure this like:

<Services> <add type="System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" UnloadOnIdle="true" LoadIntervalSeconds="5" /> </Services>

You can add the Tracking Service by doing something very similiar:

<Services> <add type="System.Workflow.Runtime.Tracking.SqlTrackingService, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> </Services>

The next step for me was very simple. At least I thought so, just combining the two services like this, didn't work:

<Services> <add type="System.Workflow.Runtime.Tracking.SqlTrackingService, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> <add type="System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" UnloadOnIdle="true" LoadIntervalSeconds="5" /> </Services>

I didn't really get an Exception of some kind. I even listened to the WorkflowRuntime.ServicesExceptionNotHandled event but nothing happened. It only seemed the Workflow didn't end with Completed but with Aborted. Yes alright but what's wrong? Tell me, please.
So again Google is my friend, and led me to the blog of Bruce Bukovics. So in the end it doesn't seam to be very difficult, it's just something you need to know. Just add the "SharedConnectionWorkflowCommitWorkBatchService" service in the config so you have a combined config like this:

<Services> <add type="System.Workflow.Runtime.Hosting.SharedConnectionWorkflowCommitWorkBatchService, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> <add type="System.Workflow.Runtime.Tracking.SqlTrackingService, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> <add type="System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" UnloadOnIdle="true" LoadIntervalSeconds="5" /> </Services>

User Event Tracking

It's possible to do some UserEvent tracking by calling the Activity.TrackData method. This method accepts a key and a value. The Tostring() method is called on the object, so there's no real serialization of the data in the object. We can off course manual serialize the data in an object. So I did some coding to make the Tracking of complex objects possible. I first thought about creating an Extensibility Method for the Activity class, but I won't be able to call the original TrackData method because it's protected. So I have the code that you can add to your custom activity to track the user event data easier.

1 public void TrackObjectData<T>(string userDataKey, T userData) where T : class, new() 2 { 3 this.TrackData(userDataKey, userData.SerializeObject()); 4 }


The code makes use of the following SerializationHelper extension methods.

1 public static class SerializationHelper 2 { 3 public static string SerializeObject<T>(this T obj) where T: class,new() 4 { 5 string result = string.Empty; 6 StringWriter stringWriter = new StringWriter(); 7 try 8 { 9 XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType()); 10 xmlSerializer.Serialize(stringWriter, obj); 11 result = stringWriter.ToString(); 12 } 13 catch 14 { 15 } 16 finally 17 { 18 if (stringWriter != null) 19 stringWriter.Close(); 20 } 21 return result; 22 } 23 public static T DeserializeObject<T>(this string xmlString) where T : class, new() 24 { 25 StringReader reader = new StringReader(xmlString); 26 T deserializedObject = default(T); 27 try 28 { 29 XmlSerializer ser = new XmlSerializer(typeof(T)); 30 deserializedObject = (T)ser.Deserialize(reader); 31 } 32 catch 33 { 34 } 35 finally 36 { 37 reader.Close(); 38 } 39 return deserializedObject; 40 } 41 }


More will follow soon
Besides this I will be looking at a few other features of Workflow Foundation that I will probably blog about. Things like implementing a workflow host and communicating with the workflow from the outside.

Gravatar