Creating a Workflow Host ApplicationĀ
The host application interacts with Windows Workflow Foundation through the WorkflowRuntime class, or a custom class that inherits from it. You create a WorkflowRuntime object and populate it with the services that you will use during the execution of your workflows.
Host application Responsibilities
The host application's responsibilities are as follows:
Create one or more processes and one or more application domains.
Provide isolation mechanisms as needed.
Marshal calls between application domains as needed.
Start workflow instances.
Create custom and local services.
Additionally, a host application might do the following:
Control the loading and unloading of workflows from memory.
Listen for specific events and communicate them to a user or administrator.
Set time-outs and retries for each workflow.
Expose performance counters.
Write log information for debugging and diagnostics.
Provide custom service implementations.
Create localized services to meet language requirements of the hosting application and user base.
Creating the WorkflowRuntime
The default mechanism for initializing Windows Workflow Foundation is to use the WorkflowRuntime class, as follows:
Imports System
Imports System.Threading
Imports System.Workflow.Runtime
Imports System.Workflow.Runtime.Hosting
Class Program
Shared Sub Main()
Using workflowRuntime As WorkflowRuntime = New WorkflowRuntime()
End Using
End Sub
End Class
using System;
using System.Threading;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;
class Program
{
static void Main(string[] args)
{
using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
}
}
}
In the using statement body, a WorkflowRuntime object is initialized and ready for use. At this point, you can create event handlers to handle events that are raised by the runtime engine, retrieve and configure any of the base services used by the runtime engine, and finally create and start a workflow instance. For more information about Windows Workflow Foundation services, see Windows Workflow Foundation Services.
Processing WorkflowRuntime Events
The Windows Workflow runtime engine raises several events throughout its lifetime that your host application can handle. These consist of events that notify your application when the runtime engine is Started or Stopped, and also several events that correspond to the lifetime of any running workflow instances. The procedure to create event handlers for these events follows the same event-handling pattern provided in the .NET Framework. As an example, the following code creates an event handler for the Started event raised by the workflow runtime when it begins execution.
AddHandler workflowRuntime.Started, AddressOf OnWorkflowStarted
...
Shared Sub OnWorkflowStarted(ByVal sender As Object, ByVal e As WorkflowRuntimeEventArgs)
Console.WriteLine("WorkflowRuntime started")
End Sub
workflowRuntime.Started += delegate(object sender, WorkflowRuntimeEventArgs e)
{
Console.WriteLine("WorkflowRuntime started");
};
The following table lists the events that can be raised by the Windows Workflow runtime engine that pertain to the workflow runtime engine itself.
Event | Description |
---|---|
Raised when a service that is derived from the WorkflowRuntimeService abstract class calls the RaiseServicesExceptionNotHandledEvent method, because an exception occurs during workflow execution that the service cannot handle. |
|
Started |
Raised when the workflow runtime engine starts running. |
Stopped |
Raised when the workflow runtime engine stops running. |
The following table lists the workflow instance events that can be raised by the workflow runtime engine.
Event | Description |
---|---|
Raised when a workflow is stopped in the middle of processing. |
|
Raised when a workflow completes processing. |
|
Raised when a workflow is instantiated. |
|
Raised when a workflow enters the idle state. |
|
Raised when a workflow is recreated from a storage medium. |
|
Raised when the current state of the workflow is persisted to a storage medium. |
|
Raised when a workflow resumes executing after it has been stopped or unloaded. |
|
Raised when a workflow starts running. |
|
Raised when a workflow enters the suspended state. |
|
Raised when a workflow is terminated. |
|
Raised when a workflow is unloaded. |
WorkflowAbort Conditions
There are several different conditions that can occur during the execution of a workflow that can raise the WorkflowAborted event. For example, a host application can intervene in the process by calling the Abort method from a WorkflowInstance object. In this case, the reason is known and the logic to handle this can easily be created in the host application itself.
There are conditions however when the Windows Workflow Foundation runtime engine will abort a workflow. An example of this condition is a result of the runtime engine failing to terminate a workflow instance. A common scenario related to this condition concerns the SqlWorkflowPersistenceService. If the workflow runtime engine needs to terminate a workflow and the SqlWorkflowPersistenceService is active, the runtime engine will attempt to persist the workflow state. However, if a SqlException is thrown during the persistence operation, the runtime engine will have to abort the workflow instance. When this occurs, you can use a TrackingService to dump the exception information in order to debug the scenario that caused the runtime engine to abort the workflow instance.
Determining Workflow Terminated Source
The WorkflowTerminated event can be raised either programmatically through the host application, by using a TerminateActivity in a workflow or as a result of an uncaught exception. If your host application needs to perform certain logic based on the type of action that caused the workflow to terminate, there are several key pieces of logic you will need to check. The following table shows different states of a workflow and where to look for information regarding the reason for termination.
Action | Workflow Status | Activity Execution Status | Terminate or Suspend Info |
---|---|---|---|
Normal Execution |
Completed |
Closed |
NULL |
TerminateActivity (Reason specified and not NULL) |
Terminated |
Executing |
Reason specified in Workflow design |
TerminateActivity (Reason is NULL) |
Terminated |
Executing |
Exception of type Workflow Terminated was thrown |
Terminated from host application |
Terminated |
Executing |
Reason specified in Terminate method parameter |
Unhandled Exception |
Terminated |
Closed |
Message of the Exception causing the termination |
Unhandled Exception in Fault Handler |
Terminated |
Closed |
Message of the Exception causing the termination |
The location in the workflow where an exception was thrown can be found by walking the workflow graph and checking the status of each Activity at the time of the termination. The following code demonstrates how to accomplish this if the exception is thrown from a FaultHandlerActivity.
Private Function isExceptionfromFaultHandler(ByVal rootActivity As Activity) As Boolean
If rootActivity Is Nothing Then
Return False
End If
If TypeOf rootActivity Is CompositeActivity Then
If TypeOf rootActivity Is FaultHandlersActivity Then
If rootActivity.ExecutionStatus = ActivityExecutionStatus.Closed Then
Return True
End If
End If
For Each act As Activity In (CType(rootActivity, CompositeActivity)).Activities
If isExceptionfromFaultHandler(act) Then
Return True
End If
Next
End If
Return False
End Function
bool isExceptionfromFaultHandler(Activity rootActivity)
{
if (rootActivity == null)
return false;
if (rootActivity is CompositeActivity)
{
if (rootActivity is FaultHandlersActivity)
{
if (rootActivity.ExecutionStatus == ActivityExecutionStatus.Closed)
return true;
}
foreach (Activity act in ((CompositeActivity)rootActivity).Activities)
if (isExceptionfromFaultHandler(act))
return true;
}
return false;
}
Running Workflows
Workflow instances can be started in two ways: Through workflow types or through XAML-based workflow markup.
To start a workflow instance through a workflow type, call the CreateWorkflow method, passing in the System.Type of the workflow, and then call Start.
Dim workflowInstance As WorkflowInstance
workflowInstance = workflowRuntime.CreateWorkflow(GetType(Workflow1))
workflowInstance.Start()
WorkflowInstance instance = workflowRuntime.CreateWorkflow
(typeof(WorkflowApplication.Workflow1));
instance.Start();
To start a workflow instance using workflow markup only, call the CreateWorkflow method, passing in the XmlReader containing the workflow definition in either a file or stream, and then call Start.
Dim workflowInstance As WorkflowInstance
workflowInstance = workflowRuntime.CreateWorkflow(workflowDefinitionReader)
workflowInstance.Start()
WorkflowInstance instance = workflowRuntime.CreateWorkflow(workflowDefinitionReader);
instance.Start();
Note |
---|
If you are using a workflow markup file with a code-separation file, you must pass the workflow type into CreateWorkflow instead of passing in the workflow markup file. |
By default, workflows are started asynchronously by the Windows Workflow runtime engine. To make sure that your host application does not close before your workflow has finished executing, you must use synchronizing threading objects that are provided by the .NET Framework, such as the AutoResetEvent object. The following code example shows how to create and start the workflow runtime, start a workflow instance, and exit by using an AutoResetEvent when the WorkflowRuntime object raises the WorkflowCompleted event.
Class Program
Shared WaitHandle As New AutoResetEvent(False)
Shared Sub Main()
Using workflowRuntime As New WorkflowRuntime()
AddHandler workflowRuntime.WorkflowCompleted, AddressOf OnWorkflowCompleted
Dim workflowInstance As WorkflowInstance
workflowInstance = workflowRuntime.CreateWorkflow(GetType(Workflow1))
workflowInstance.Start()
WaitHandle.WaitOne()
End Using
End Sub
Shared Sub OnWorkflowCompleted(ByVal sender As Object, ByVal e As WorkflowCompletedEventArgs)
WaitHandle.Set()
End Sub
End Class
static void Main(string[] args)
{
using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
AutoResetEvent waitHandle = new AutoResetEvent(false);
workflowRuntime.WorkflowCompleted += delegate(object sender,
WorkflowCompletedEventArgs e)
{
waitHandle.Set();
};
WorkflowInstance instance = workflowRuntime.CreateWorkflow
(typeof(WorkflowApplication.Workflow1));
instance.Start();
waitHandle.WaitOne();
}
}
Windows Workflow Foundation does not have any restrictions on the execution environment of the hosting application. For instance, some host application environments may require that several processes execute in several application domains, each with its own threading model independent of the other executing processes. In this way, Windows Workflow Foundation remains portable and extensible as underlying hosting architectures change.
Note |
---|
Windows Workflow Foundation uses the .NET thread pool. If your host application is multi-threaded and uses the .NET thread pool extensively, you may starve the .NET thread pool. This could cause timeouts when a persistence service tries to complete a persistence transaction because Transaction objects also use the .NET thread pool. |
See Also
Reference
WorkflowRuntime
Start
CreateWorkflow
Started
Stopped
ServicesExceptionNotHandled
WorkflowAborted
WorkflowCompleted
WorkflowCreated
WorkflowIdled
WorkflowLoaded
WorkflowPersisted
WorkflowResumed
WorkflowStarted
WorkflowSuspended
WorkflowTerminated
WorkflowUnloaded
Concepts
How to: Add and Remove Workflow Services
Workflow and Application Communication
Other Resources
Windows Workflow Foundation Services
Developing Workflow-Enabled Applications
Send comments about this topic to Microsoft.