I'm trying to write fullblown WF persistence service, and so far I was good.
I had no problems with Instance save/load methods. But now I stuck with Load/Save CompletedActivity...
How do I get ContextGuid of the completed activity, if all DependencyProperties are internal/private
Documentation points to void pages How do I something like this in non-MS assembly:
Guid contextId = ((ActivityExecutionContextInfo)activity.GetValue(Activity.ActivityExecutionContextInfoProperty)).ContextGuid;

WorkflowPersistence question
Ziga
Did you try this
Guid contextGuid = (Guid)activity.GetValue(Activity.ActivityContextGuidProperty);
D Wagner
That is much simpler!
Thanks a lot. Coming a bit further...
Hari G
OK. Here are my conclusions about "how to write persistence service" for any database.
1. You need 3 tables in database. Workflows, Timer & Scopes... In table Workflow you'll save workflow instance data, in Timers - next timers for a workflow, in Scopes - currency transaction scopes if any.
Structure of Workflow table is like this:
WorkflowId GUID (PK), WorkflowStream BLOB, ... some additional fields like Status, State, ErrorText etc...
Structure of Timers table is very simple:
WorkflowId GUID (PK, Foreign key to Workflow.WorkflowId, on delete cascade), NextTimer DATE
Structure of Scopes:
ScopeId GUID (PK), WorkflowId GUID (Foreign key to Workflow.WorkflowId, on delete cascade), ScopeStream BLOB
Now we have 6 methods to implement. Some hints what to do there...
protected override Activity LoadWorkflowInstanceState(Guid id);
In this method, we load blob from table Workflows where WorkflowId=id and return Activity.Load(blobStream);
protected override Activity LoadCompletedContextActivity(Guid id, Activity root);
In this method, we load blob from table Scopes where ScopeId=id and return Activity.Load(scopeStream, root);
protected override void SaveCompletedContextActivity(Activity root);
In this method, we save root.Save(ScopeStream) into table Scopes, we may get ScopeId like this:
Guid ScopeId = (Guid)activity.GetValue(Activity.ActivityContextGuidProperty);
WorkflowId like this:
Guid WorkflowId = WorkflowEnvironment.WorkflowInstanceId;
protected override void SaveWorkflowInstanceState(Activity root, bool unlock);
In this method, we save blob into table Workflows where WorkflowId=id. Also here you should save next active timer for this workflow if any.
TimerEventSubscriptionCollection timers = (TimerEventSubscriptionCollection)root.GetValue(TimerEventSubscriptionCollection.TimerCollectionProperty);
TimerEventSubscription subscription = timers.Peek();
If there is a subscription, we make an entry for this timer in Timers table. You also need a Threading.Timer, which will always load workflow of the next available timer and delete timer record from Timers table.protected override bool UnloadOnIdle(Activity activity);
Here we always return true. IMHO, all workflows should be unloaded on idle.
protected override void UnlockWorkflowInstanceState(Activity root);
Here I personally do nothing, 'cause I have no locking mechanism and plan to use only 1 persistence service at a time.
Good luck, hope someone will find this post useful.