One of the most important technical considerations when you’re determining whether to use Windows Workflow Foundation with ASP.NET is the hosting of the workflow runtime. By default, the workflow runtime is hosted so that new workflow instances are executed asynchronously, on a separate thread from the runtime. This generally works great, especially in applications that have a user interface because the work goes on in the background and the user interface thread is freed up to respond to user interaction. However, this is a different story in ASP.NET, for a couple of reasons.
First, workflows might need to behave differently in web applications because of the way users interact with web forms. When a button is clicked, a round trip is performed, and a response page is generated and returned to the user after the work on the server is complete. Because of this, and if the workflow steps are short in duration, the work should probably take place on the same thread as the web response so that control is not returned to the user until the workflow has completed a unit of work.
In addition, there are threading considerations because of the fact that ASP.NET is hosted in the IIS web server. IIS is particular about having many of its threads consumed. Because of this, the Windows Workflow Foundation API provides a scheduler service as an alternative to DefaultWorkflowSchedulerService. You can add ManualWorkflowSchedulerService to the workflow runtime’s services just as you would any other runtime service. Instead of launching workflow instances on their own thread, ManualWorkflowSchedulerService executes instances on the calling thread in a synchronous manner.
The following is an example of using the ManualWorkflowSchedulerService:
WorkflowRuntime runtime = new WorkflowRuntime(); ManualWorkflowSchedulerService schedulerService = new ManualWorkflowSchedulerService(); runtime.AddService(schedulerService); WorkflowInstance instance = runtime.CreateWorkflow(typeof(MyWorkflow)); instance.Start(); // the workflow instance is still not running! // start it using the scheduler service schedulerService.RunWorkflow(instance.InstanceId);
As you can see in the code, this is different from the DefaultWorkflowSchedulerService in that the ManualWorkflowSchedulerService requires an additional method call to start instance execution - even after the WorkflowInstance.Start method is called. The RunWorkflow method takes an instance GUID and causes a blocking call until the workflow returns control to the host application. Remember that if the RunWorkflow method is not called by the host, the workflow instance never executes.
This type of scenario makes perfect sense in an ASP.NET application that hosts a workflow with bite-size chunks of execution - meaning that a page request calls a workflow that performs work that does not take more than a few seconds. However, even for scenarios in which the workflow takes extended periods of time to execute and return control to the caller, using the DefaultWorkflowSchedulerService might not be the answer. Execution in web applications is generally reserved for performing work that has some impact on a page’s outcome. Instead of using background threads for long-running work that will not be later utilized by a page, you can offload this work to an outside application. This type of scenario is discussed in Chapter 14, using a Windows Service as a workflow runtime host that runs outside the context of ASP.NET and IIS.