WorkflowPersistenceService.SaveWorkflowInstanceState(Activity, Boolean) Method

Definition

When implemented in a derived class, saves the workflow instance state to a data store.

protected public:
 abstract void SaveWorkflowInstanceState(System::Workflow::ComponentModel::Activity ^ rootActivity, bool unlock);
protected internal abstract void SaveWorkflowInstanceState (System.Workflow.ComponentModel.Activity rootActivity, bool unlock);
abstract member SaveWorkflowInstanceState : System.Workflow.ComponentModel.Activity * bool -> unit
Protected Friend MustOverride Sub SaveWorkflowInstanceState (rootActivity As Activity, unlock As Boolean)

Parameters

rootActivity
Activity

The root activity of the workflow instance.

unlock
Boolean

true if the workflow instance should not be locked; false if the workflow instance should be locked.

Examples

The following example demonstrates an implementation of the SaveWorkflowInstanceState method. This example is from the Custom Persistence Service sample, from the FilePersistenceService.cs file. For more information, see Custom Persistence Service Sample.

// Save the workflow instance state at the point of persistence with option of locking the instance state if it is shared
// across multiple runtimes or multiple phase instance updates
protected override void SaveWorkflowInstanceState(Activity rootActivity, bool unlock)
{
    // Save the workflow
    Guid contextGuid = (Guid)rootActivity.GetValue(Activity.ActivityContextGuidProperty);
    Console.WriteLine("Saving instance: {0}\n", contextGuid);
    SerializeToFile(
        WorkflowPersistenceService.GetDefaultSerializedForm(rootActivity), contextGuid);

    // See when the next timer (Delay activity) for this workflow will expire
    TimerEventSubscriptionCollection timers = (TimerEventSubscriptionCollection)rootActivity.GetValue(TimerEventSubscriptionCollection.TimerCollectionProperty);
    TimerEventSubscription subscription = timers.Peek();
    if (subscription != null)
    {
        // Set a system timer to automatically reload this workflow when its next timer expires
        TimerCallback callback = new TimerCallback(ReloadWorkflow);
        TimeSpan timeDifference = subscription.ExpiresAt - DateTime.UtcNow;
        System.Threading.Timer timer = new System.Threading.Timer(
            callback,
            subscription.WorkflowInstanceId,
            timeDifference < TimeSpan.Zero ? TimeSpan.Zero : timeDifference,
            new TimeSpan(-1));
    }
}
' Save the workflow instance state at the point of persistence with option of locking the instance state if it is shared
' across multiple runtimes or multiple phase instance updates
Protected Overrides Sub SaveWorkflowInstanceState(ByVal rootActivity As System.Workflow.ComponentModel.Activity, ByVal unlock As Boolean)
    Dim contextGuid As Guid = CType(rootActivity.GetValue(Activity.ActivityContextGuidProperty), Guid)
    Console.WriteLine("Saving instance: 0}" + vbLf, contextGuid)
    SerializeToFile( _
        WorkflowPersistenceService.GetDefaultSerializedForm(rootActivity), contextGuid)

    ' See when the next timer (Delay activity) for this workflow will expire
    Dim timers As TimerEventSubscriptionCollection = CType(rootActivity.GetValue(TimerEventSubscriptionCollection.TimerCollectionProperty), TimerEventSubscriptionCollection)
    Dim subscription As TimerEventSubscription = timers.Peek()
    If subscription IsNot Nothing Then
        ' Set a system timer to automatically reload this workflow when it's next timer expires
        Dim timeDifference As TimeSpan = subscription.ExpiresAt - DateTime.UtcNow
        Dim callback As TimerCallback = New TimerCallback(AddressOf ReloadWorkflow)
        Dim timer As New System.Threading.Timer( _
            callback, _
            subscription.WorkflowInstanceId, _
            CType(IIf(timeDifference < TimeSpan.Zero, TimeSpan.Zero, timeDifference), TimeSpan), _
            New TimeSpan(-1))
    End If
End Sub

Remarks

You must call one of the overloaded Save methods to serialize rootActivity into a Stream. You can then choose to additionally process the Stream before writing it to your data store. However, when the workflow runtime engine calls LoadWorkflowInstanceState, you must restore an identical copy of the root activity. If you cannot save the workflow instance state to your data store, you should throw a PersistenceException with an appropriate error message.

The workflow runtime engine provides locking semantics to restrict access to a workflow instance state that is saved in the data store. This can be accessed by the persistence services running in multiple hosts and pointing to the same data store. The locking semantics are designed to prevent persistence services that run in two different workflow runtimes from loading the same workflow instance into memory at the same time. Depending on the type of environment your persistence service is designed to support, you can choose whether to support this functionality. If you choose to support the runtime locking semantics, then, if a persistence service tries to save a workflow instance state that has been previously locked by another persistence service, you should throw a WorkflowOwnershipException. If unlock is true, you should unlock access to the workflow instance state after you save it.

LoadWorkflowInstanceState takes the Guid of the workflow instance as a parameter. Therefore, you should save this Guid. You can also use this Guid to associate the workflow instance with the saved states of its completed scopes. You must do this because you must be able to mark these completed scopes as unneeded when the workflow instance completes.

The workflow runtime engine calls SaveWorkflowInstanceState a final time when the workflow instance is completed or terminated. Therefore, if GetWorkflowStatus is equal to Completed or Terminated, you can safely delete the workflow instance and all its associated completed scopes from your data store. Alternatively, you can subscribe to the WorkflowCompleted or WorkflowTerminated events to determine when it is safe to delete records associated with the workflow instance. Whether you actually delete the records from your data store depends on your implementation.

If you implement a persistence service that uses a durable store, then, to maintain consistency with the internal state of the workflow runtime engine, you should participate in workflow transaction batching to defer the actual write to your durable store until a workflow commit point. To participate in batching, add a work item that represents the pending changes to your durable store to the WorkBatch property, and implement the IPendingWork interface in your persistence service.

Applies to