A Simple Workflow MVC Example
To demonstrate this idea, I'll show you a simple ASP.NET application and workflow. The oversimplified workflow describes a process that collects some personal information from an external application, and then displays it. Here are the steps:
|Figure 1. Sample Workflow: This workflow describes the procedures implicit in the sample ASP.NET application.|
- Call a method that signifies a request for a person's name; the workflow uses the InvokeMethod activity (see Figure 1).
- Wait until an event is fired signifying the receipt of a name; the workflow uses the EventSink activity for this step.
- Obtain an e-mail address from the host using a similar call.
- Wait for an event signifying the receipt of the address.
- After receiving both the name and e-mail address the workflow launches an InvokeMethod activity to send the personal data to the calling application. This last step does not make much sense in a real-world scenario. More likely, you'd call a Web service to send the data to some other system, or place it into a database.
To implement this workflow in ASP.NET you need a page to collect a person's name, a page to collect the email address, and a page that displays the personal data. Remember, the data entry forms should know nothing about what has happened before or what happens next. The same goes for the display page. However, the ASP.NET application has to somehow know which page to display to the user; this where the controller comes in. This example uses an HttpHandler to implement the solution. The custom handler, called WorkflowControllerHandler
, deals with the following tasks:
- Obtaining a reference to the workflow runtime.
- Obtaining a reference to or starting a new workflow instance (depending on whether a workflow instance is already started).
- Setting up communications between the controller and the workflow.
- Handling events from the workflow.
- Telling ASP.NET which page needs to be displayed depending on which stage in the workflow is currently being executed.
As you can see, the custom handler essentially takes care of all the dirty work related to Windows WF and page control, letting the individual ASP.NET pages remain "dumb" about what's going on behind the scenes. The only thing the Web forms need to worry about is performing the specific task at hand and passing the necessary data to the controller.
By default, Windows WF works in an asynchronous model. This means that when an application host starts a workflow instance, control immediately returns to the host while workflow execution continues on another thread. This can be very useful in a Windows Forms application where continual responsiveness of the user interface is highly desirable. Using the asynchronous model the workflow executes in the background and the user can continue to manipulate the application. In a Web application, however, this type of behavior may not
be desirable, because control would usually only be returned to the user after the server completes a unit of work. This is where the extensibility of Windows WF shines. In Windows WF, developers can utilize or write "runtime services" to monitor and even modify the workflow runtime. Examples include:
- Persistence services that store workflow state between execution and idle time.
- Tracking services that output information about workflow execution to some medium
- Transaction services that help maintain data integrity in the workflow execution process
In addition, threading services let developers control how workflow instances are executed. As discussed, the workflow runtime will by default run instances asynchronously, on a separate thread from the host. But as this is probably not desirable in ASP.NET, you need to swap out the default workflow threading service. Luckily, Microsoft already provides a solution for such a purpose, the ASPNetThreadingService. To make this change, you can either manually add the ASPNetThreadingService to the workflow runtime services in code, or do it in the web.config
file. The sample application uses configuration. In the WorkflowRuntime/Services section of the web.config (see Listing 1)
, add a line similar to the following: