There are two ways to communicate information with a workflow through its hosted runtime. First, data can be sent to the workflow via parameters. When a workflow starts up and runs it can process that data sent to it, however during the workflow’s lifecycle, the initial data sent to the workflow can change. With short-running workflows where the workflow host continues to run while the workflow finishes, the workflow throws a “workflow completed” event and passes the processed data to the host.
The second way to pass data to a workflow is through events, and if the workflow is again short-running, then you could use CallExternalMethod Activities to raise local service events to the hosted runtime to pass back processed data. But what if the workflow is long-running? What happens if multiple applications need to re-hydrate the workflow for processing? Is data sent to the workflow via events persisted too? Sure it is… and it is very easy to retrieve.
So let’s already assume that you have need for a long running workflow that will be persisted by default when it becomes idle. You have also created a local service with events and added it to the host to communicate with workflows, by passing “args” to it. Make sure that Parameters “e” property (found in the property window) for each HandleExternalEvent activity that implements an event from the local service is set to a local workflow variable of its type. Next, when the “SQLWorkflowPersistenceService” service is added to the runtime, it should have a reasonable lock-time on each persisted instance (about 5 minutes or more), and call, “StopRuntime()” to STOP the runtime rather than just killing the runtime host during debugging, to avoid situations when trying to unload workflows that the runtime still thinks are in memory.
There is a workflow method that is called each time that it loads called, “OnActivityExecutionContextLoad”, and a property called, “UserData” that all activities derive from that objects can be added.
The following code verifies if the eventargs, local property in the workflow has been set. If so, it adds the property to a collection and gives the item a distinct key. In this case, it makes more since to make the key the same as the instanceID of workflow instance.
private Movie.RentalArgs _rental; //Property set by HandleExternalEvent activities
public Movie.RentalArgs Rental
{
get { return _rental; }
set { _rental = value; }
}
protected override void OnActivityExecutionContextLoad(IServiceProvider provider)
{
if (_rental != null)
this.UserData.Add(_rental.InstanceId, _rental);
}
Finally, the workflow host should check to see if there are any persisted workflow instances. When a persisted instance is identified, the following code shows how to get the workflow definition, to get to the “UserData” property that was set when the workflow loaded.
private void LoadPersistedWorkflows()
{
Activity Act;
IEnumerable PersistedInstances = null;
PersistedInstances = _persistanceService.GetAllWorkflows();
foreach (SqlPersistenceWorkflowInstanceDescription Instnc in PersistedInstances)
{
_wfInstance = _wfRuntime.GetWorkflow(Instnc.WorkflowInstanceId);
Act = wfInstance.GetWorkflowDefinition();
_rental = Act.UserData[_wfInstance.InstanceId] as Movie.RentalArgs;
}
}
Retrieval of data that is initially sent to workflows can be important. Expecially if that data could change over the lifecycle of the workflow. In some cases, it may be appropriate to store this data outside of the workflow, however you still may need to populate screens with data from the workflow, based on the state of workflow.