We already discussed about Persistence and Extensions in workflow foundation 4.0. Persistence is the way of storing the current state of a workflow into an instance store. Extensions are special classes for sharing data among child activities, workflow and Host application. In case of normal Extension, the data shared using the Extension won’t be stored to the instance store as part of the Persistence.
Introduction
We already discussed about Persistence and Extensions in workflow foundation 4.0. Persistence is the way of storing the current state of a workflow into an instance store. Extensions are special classes for sharing data among child activities, workflow and Host application. In case of normal Extension, the data shared using the Extension won’t be stored to the instance store as part of the Persistence.
In real business scenario, we may need to store the Extension data as part of the workflow state. For this purpose, workflow foundation 4.0 is providing a special kind of Extension. In this article we will discuss about this special extension and how we can use the same.
PersistenceParticipant Extension
This special extension is a class which inherited from the System.Activities.Persistence.PersistenceParticipant base class. For implementing the PersistenceParticipant, we need to override two methods CollectValues and PublishValues.
Here, for our sample we have small Persistence Participant extension which stores a collection of strings in an Items list. Same way we have a normal extension class to store the data in an Items list.
Normal Extension
For more details on Extension, please refer Workflow Foundation 4.0 - Extension
public class NormalExtension
{
private List<object> items = new List<object>();
public List<object> Items
{
get
{
if (items == null)
{
items = new List<object>();
}
return items;
}
}
}
PersistenceParticipant Extension
As the Items list is a read write property, in CollectValues method, we need to assign the Item value to readWriteValues and assign null to writeOnlyValues. In PublishValues method, extract the Items value from readwriteValues dictionary and assign to Items property.
public class MyPersistenceParticipant:PersistenceParticipant
{
static XNamespace myNamespace = XNamespace.Get("MyApp");
static XName currentItems = myNamespace.GetName("Items");
private List<object> items = new List<object>();
public List<object> Items
{
get
{
if (items == null)
{
items = new List<object>();
}
return items;
}
}
protected override void CollectValues(out IDictionary<XName, object> readWriteValues, out IDictionary<XName, object> writeOnlyValues)
{
readWriteValues = new Dictionary<XName, object>(1) { { currentItems, this.items } };
writeOnlyValues = null;
}
protected override void PublishValues(IDictionary<XName, object> readWriteValues)
{
object loadedData;
if (readWriteValues.TryGetValue(currentItems, out loadedData))
{
items = (List<object>)loadedData;
}
}
}
Workflow
For understanding the difference between the normal extension and Persistence participant, we have a small workflow.
Here Close_Bookmark is a custom activity to create bookmark with name “Close”. For more details on Bookmark, please refer Workflow Foundation 4.0 – Bookmark.
Host application
For verifying our Persistence Participant extension, we will use the following Host application code.
Create an Instance of the workflow application and set the Instance Store. After that, add the objects of Normal as well as PersistenceParticipant extensions with one Item added to the Items property to the Extension collection of our workflow application.
For our sample, we need to unload the instance completely from memory, so called the Unload method instead of Persist method. This will store the workflow state to instance store and remove the workflow application object from memory.
Now, for reloading the workflow from instance store, create the workflow application object, setup instance store and add extension objects to the workflow application object. After reloading, loop through the Items collection of both normal extension and PersistenceParticipant extension and display the items.
static void Main(string[] args)
{
WorkflowApplication wfApp = new WorkflowApplication(new Workflow1());
InstanceStore store = new SqlWorkflowInstanceStore(@"Data Source=.;Initial Catalog=SqlWorkflowInstanceStore;Integrated Security=True");
wfApp.InstanceStore = store;
NormalExtension normalObj = new NormalExtension();
normalObj.Items.Add("Normal Extension: Before Persist");
MyPersistenceParticipant obj = new MyPersistenceParticipant();
obj.Items.Add("Persistence Participant Extension: Before Persist");
wfApp.Extensions.Add(normalObj);
wfApp.Extensions.Add(obj);
Guid persistId = wfApp.Id;
wfApp.Run();
wfApp.Unload();
WorkflowApplication wfApp1 = new WorkflowApplication(new Workflow1());
wfApp1.InstanceStore = store;
NormalExtension normalObjAfter = new NormalExtension();
MyPersistenceParticipant objAfter = new MyPersistenceParticipant();
wfApp1.Extensions.Add(normalObjAfter);
wfApp1.Extensions.Add(objAfter);
wfApp1.Load(persistId);
foreach (string s in normalObjAfter.Items)
{
Console.WriteLine(s);
}
foreach (string s in objAfter.Items)
{
Console.WriteLine(s);
}
wfApp1.ResumeBookmark("Close", null);
Console.Read();
}
Result
From the result screen, we can observe that the data added to the PersistenceParticipant extension before Persist operation persisted as part of workflow state information. And the data added to the normal extension before Persist operation is not available after reloading of the workflow.
Conclusion
PersistenceParticipant is a special extension for storing additional data along with the workflow state to the Instance store on Persisting a workflow. We can use normal extension for sharing data across different activities, workflow and host application. If the data needs to be persisted along with workflow state, then use the PersistenceParticipant Extension.