WorkflowPersistence question

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;



Answer this question

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.


  • WorkflowPersistence question