.NET Windows Workflow Foundation is a great multithread-based framework, which not only helps to declare your workflow (your business logic) and helps to define the logic and control flow, but also provides a runtime for executing your application definition, with the goal of making developers more productive, applications easier to manage, and change quicker to implement. On the other hand, ASP.NET MVC framework is also a great and new framework aiming to simplify large and complex web applications development, which has been attracting more and more developers especially the new developers' attention. So, as hinted from the title, this article aims to as an elementary tutorial to help you to put the two together by constructing a simple multiple-step based registration web application, with WF 4.0 depicting the business flow and ASP.NET MVC 2.0 framework implementing the application.
The development environments and tools we'll use in the sample application are:
1. Windows XP Professional (SP3);
2. .NET 4.0;
3. Visual Studio 2010 (with built-in WF 4.0 support);
4. WF State Machine Activity Pack CTP 1 (http://wf.codeplex.com/releases/view/43586);
Let's first build up the prerequisites for facilitating establishing the registration sample application.
Install WF State Machine Activity Pack CTP 1
Note inside VS2010 built-in Workflow 4.0, there has not provided better support for State Machine based Activity. Although you can achieve this indirectly through Flowchart related components it's rather complex. For this, Microsoft provides an unofficial version at codeplex (http://wf.codeplex.com/releases/view/43586) named WF State Machine Activity Pack CTP 1.
The Microsoft WF State Machine Activity Pack CTP 1 is the first community technology preview (CTP) release of a state machine implementation based on Windows Workflow Foundation in .NET Framework 4 (WF 4). The implementation contains not only a state machine runtime but also a graphical state machine designer. As a result, you can use it in much the same way as that in WF 3.0. And as the same time, some of the State Machine related operations get greatly simplified.
To make preparation for our sample application, the following installation steps should be followed:
1. Shut down your VS2010.
2. Download WF State Machine Activity Pack CTP 1 from the above-mentioned url and run the setup file Microsoft_WF_State_Machine_Activity_Pack_CTP_1_Setup.msi (352KB). Click Allow if the User Account Control dialog pops up. Since the next steps are simple we are not going to detail them any more.
3. Now launch again your VS2010 and create a simple Console Workflow application. Then in the toolbox you will notice the newly-added state machine related components, as shown in Figure 1 below.
Figure 1: The new StateMachine related components supplied by Microsoft WF State Machine Activity Pack CTP 1
Create the Sample Application Sketch
1. Start up Visual Studio 2010, and then create a blank solution named MVC2_WF4_Registration.
2. Right click the solution and select "Add| New Project..." to add a new ASP.NET MVC 2 Web Application named MVC_Registration. For simplicity, we don't select to add the related unit test project in the subsequent dialog.
3. Again right click the above solution, select "Add| New Project..." to add a new Workflow Activity Library, and name it Workflow4.
Till now, we've finished creating the sample application sketch. Next, we'll start the real interesting work.
Create the Workflow Library
As you've guessed, since our sample application will only supply the registration functionality, it is very simple. Anyway, let's first figure out the flow process using the visual workflow tool. Figure 2 indicates the finished form of the StateMachine.
Figure 2: The finished form of the StateMachine
Let's first say a few words about the workflow. In earlier versions of .NET frameworks, there have been introduced two kinds of workflows: Sequential Workflow and State Machine Workflow. State machine workflows are designed to work in event-driven scenarios. A state machine workflow contains two or more states, with one state being the active state at any given time. WF 4.0, however, does not support state machine workflows any more. In fact, WF 4.0 is a completely new design – it introduces a whole new paradigm for building workflow-based applications. As mentioned above, if you have some idea of WF 3.X, you will notice that you can nearly achieve the same target that can be done using the previous State Machine Workflow through the newly-introduced Flowchart Workflow. In my personal opinion, at least for this reason, Microsoft has also brought an old-styled state machine-based workflow at codeplex, which will be used in this article.
In this article, we are going to create a state machine-based workflow that handles registration steps from outside the host application (an ASP.NET MVC 2.0 based web application) and processes the registration data through different states in the workflow. Please note in WF 4.0 the initial state merely represents the start of the state machine without any more significations. So, the "true" initial state is Step1 (as shown in the above figure), which corresponds to the first step in the whole registration steps that will executes as soon as the ASP.NET MVC host application starts up. Upon receipt of the personal info and the button "Next>" clicked, the state machine will go to the next step – Step2 where the user's post info will be filled, and so on. The final state corresponds to the factual final state - Final.
Delve into the StateMachine
To make novice readers gain a better understanding with the above state machine related programming, let me detail into the first step related operations. As for other steps, they are nearly the same.
As soon as you add the new Activity Library in the preceding step, the Activity1.xaml (for simplicity, we do not rename it) file will be automatically opened, ready to add state machine related components.
Now, you can follow the subsequent steps to design the state machine.
1. Drag the component StateMachine onto the point where there is a prompt "Drop activity here". Then you get the result in Figure 3.
Figure 3: StateMachine Activity with Default Initial State
2. Rename the
DisplayName property from State to
Step1. Then, double click it and drag a custom Activity
WaitForInput<T> onto the Entry area. Here,
WaitForInput<T> is a custom Activity, to be discussed later on. Click the activity node, change the
BookmarkName to Step1, rename the
DisplayName property to
Next, and fill in the
input value using
command is Variable (newly-introduced in WF 4.0), used as a global variable to control the state transition. Figure 4 gives the related snapshot.
Figure 4: Drag a custom Activity WaitForInput onto the Entry area
In this case, as shown in Figure 4, just leave the Exit related area empty.
3. Click the item StateMachine at the breadcrumb at the top to return to the top level. From the Toolbox, drag a FinalState in the State Machine category and drop it on the designer surface.
4. Add the rest states, Step2, Step3, and Step4, onto the StateMachine. Note do the same things as with Step1 in the Entry actions.
5. Add a transition from the Step1 state to the state Step2. To do this, move your mouse over the Step1 state; select a connection point shown at the border of the state and drag to create a link. Then, keep your mouse press down and move it over the state Step2 then release your mouse.
Transition is a directed relationship between two states which represents the complete response of a state machine to an occurrence of an event of a particular type.
6. Double click the transition line (from Step1 to Step2) to open the transition designer. Then drag a WriteLine Activity from the Primitives tab into the Trigger area, setting the
Text property of the WriteLine activity to "Step1". And then, specify the
command=”Next". Please refer to Figure 5 concerning how to configure the trigger and action of the transition.
Figure 5: Use the transition designer to specify the trigger and condition
7. Navigate back to the state machine view using the breadcrumb at top of the designer.
8. Add a self-transition on "Step1". A self-transition is a transition which transits from a state to itself. It is very useful when you want to model a loop in your state machine. You will usually set the
Condition property of a self-transition to define the exit logic of the loop, which makes the self-transition a conditional transition as well.
a. Move your mouse over the "Step1" and select a connection point shown at the border of the state and drag to create a link.
b. Keep your mouse press down and move it over "Step1" itself then release your mouse. This will create a self-transition on "Step1".
c. And then, specify the
d. Manually layout the self-transition if needed.
9. Double click the self transition to open the transition designer. Then configure the self transition, as shown in Figure 6.
Figure 6: Configure Self-transition
For brevity, we are not going to dwell upon other states since they are quite similar to the state Step1.
Create a Bookmark-enabled Custom Activity
It is worth noticing WF 4.0 introduces a bookmark mechanism. Using bookmarks, you are able to suspend a workflow instance and save a marker so the instance can be resumed exactly where it left off. They are designed to receive data upon resumption.
A bookmark is generally created in a custom activity. In this case, you'll create a generic activity that can be reused wherever a bookmark is required.
In the Solution Explorer, right-click the Workflow4 project and choose Add | Class. Enter WaitForInput.cs as the file name. The complete implementation for this class is shown in Listing 1.
This custom activity uses the NativeActivity base class (instead of CodeActivity) because this gives it access to the NativeActivityContext, which is required when creating a bookmark. It also uses the template version (note the <T> in the class name). The
Input argument represents the data that is passed into the workflow when it is resumed. By using the template version, this activity can be reused with any data type.
Execute method calls the
CreateBookmark method of the NativeActivityContext, specifying the bookmark name and a reference to the callback method named
Continue. When the workflow is resumed, this callback method is executed. Notice that the callback method receives an object as the third parameter. This is the data provided by the application. It is stored in the Input argument, making it available to the workflow.
Finally, please note that activities that use bookmarks must override the
CanInduceIdle property to return true. This allows the workflow to enter the Idle state while waiting for the bookmark to resume. In this sample, however, you seemingly will not find this because what we need to do is just drag it onto the Entry area of the state StepX.
By the way, as soon as you create the above custom activity and build the project, you will see the custom activity related component appearing inside the toolbox in a tab named Workflow4 (just the project name). Then you can drag it onto the places as mentioned above.
Last, build the workflow project. And then, open up the web project MVC_Registration and add reference to the workflow assemble Workflow4.dll.
Starting from the next section, we will shift our attention to build up the ASP.NET MVC 2 project.
Set up the ASP.NET MVC Web Project
In this section, we'll focus our attention to what we should do in the MVC side.
Create a Helper Class to Host the Workflow
To facilitate using the workflow library in the ASP.NET MVC web application, we'd better create a helper class to encapsulate it, as well as add other related operations.
Now, right click the MVC project MVC_Registration to add a new class named WorkflowUtil. The related code is given below.
As you've noticed, here we created a wrapper class WorkflowUtil to help to control the asynchronous running of the workflow. To do this, we introduced an important AutoResetEvent object with which you can shut down the application when the workflow has finished executing. For details about AutoResetEvent, please refer to related materials on MSDN.
Next, note in the method StartWorkflow, we passed the definition of the workflow - Activity1 into the WF 4.0 newly-introduced constructor WorkflowApplication. And next, we subscribed to two events –
Idle, through which and together with the preceding AutoResetEvent object we achieved controlling the termination of the workflow instance.
The next method RunWorkflow will be invoked in the MVC controller, to be discussed later.
In WF 4.0 there are at least two ways to start a workflow: via the Invoke() method and via the Run() method. However, the Invoke() method approach will start the workflow synchronously; the workflow will execute on the caller's thread. This means that the application will be blocked until the workflow becomes idle. That's may be not what you want in your project. So, if you want to start the workflow on its own thread while the application can continue to respond to events (and incoming messages) you can use the Run() method to accomplish this.
Create the User Model
Since this registration sample is mainly used to illustrate how to integrate WF 4.0 into ASP.NET MVC 2.0 application development, we have created a very simple data model class named User. Listing 3 indicates the detailed definition.
Listing 1: Define the User model
Note herein the server-side validation technique, through the built-in Data Annotations attributes, has been leveraged to validate the model data. For example, the
Required attribute causes the built-in DataAnnotationsValidatorProvider to validate this property as a required field, with which the
ErrorMessage parameter is used to display the related error message. Another meta attribute
StringLength specifies the maximum length of the string property.
Create the UserController Controller
OK, now let's create a User controller to work with the above User model, as shown in Listing 4 below.
Listing 2: Define the UserController controller
In the above controller, we defined an important action method
Process, with which we can achieve the target to communicate with the workflow. At the beginning, if the static property
wrkFlw is null, we create an instance of the helper class WorkflowUtil and pass it to wrkFlw. And then, we execute the
return View(page, userObj); statement, when the page is equal to "Step1" (the default value).
Next, when the user clicks the button "Next>" on the web page, again the action method
Process in the User controller will be invoked. At this time, the condition
nextButton != null is met, when the following code is executed:
By calling the method
RunWorkflow of the instance of the helper class WorkflowUtil passing the string "Next" as the argument, the workflow will retrieve the bookmark name. And then, the bookmark will be resumed with the specified name, using the specified command. If the workflow has not ended, the next bookmark name will be retrieved and return the name. This just corresponds to the next view name such as "Step2", "Step3", etc. Please refer to related code in the
RunWorkflow method in the helper class WorkflowUtil. Now back in the above method
Process, the corresponding view will be invoked with the right User model data passed in.
Also, please notice the other two methods,
OnActionExecuting method will be called before the action method Process is invoked, while the
OnResultExecuted method gets called after the action result that is returned by an action method is executed. Both the two functionalities should owe to the newest AOP (Aspect-Oriented Programming) support introduced in ASP.NET MVC 2.0, with which we can easily handle the data (through the TempData directory structure in this case)used by the Views.
Create the Registration Steps Related Views
Till now, creating the registration steps related views is pretty easy. What we need to do is just right click the above
Process method and select "Add View". Figure 7 shows the "Add View" dialog when creating the view Step1.
Figure 7: Use the “Add View” dialog to help to quickly create interested view
After that, the system will automatically switch the control to the view design state. Listing 5 indicates the code related to the view Step1.
Listing 3: The view Step1 related code
First, easily seen, the above code created only one simple form via ASP.NET MVC specific syntax. Next, we used the
ValidationMessageFor method to define the property in the model to suck in the validation rules for, and the placeholder to put the error message if the validation fails. Third, note ASP.NET MVC 2 ships with a whole new group of methods suffixed with
For, such as
CheckBoxFor, etc. With these methods we can use a lambda to select the property within the model to use to display the UI. In our "Stepx" views design, we've widely utilized these methods to simplify the model binding operations. For other views, please refer to the downloaded source code.
Set up the Routes in File Global.asax.cs
At last, let's look at the route related programming. In ASP.NET MVC environment, a simple way to schedule the routes used in the whole application can be manipulated through the file Global.asax.cs. Listing 6 gives the routing definitions in our case.
Note above we set the two parameters,
backButton, both optional, so that in the Web pane in our MVC project property dialog we can set the "Start Action" to "Specific Page" with "User/Process", as shown in Figure 8 below.
Figure 8: Use the specific page way to test our registration steps controlled by WF 4.0
Start up the Application and Visualize the Finished Lines
As mentioned previously, before starting up the MVC sample application, we should first build the above workflow project Workflow4 first. And then, set proper project dependency – the MVC project MVC_Registration depends upon the project Workflow4. In fact, there are no strict order in the above two steps if both of them are located in the same machine. Next, we should open the MVC project MVC_Registration and add necessary reference to the assemble Workflow4.dll. At last, let's rebuild the whole solution. If everything goes well, then we can run the sample application.
Press F5 or Ctrl+F5 to run the MVC application, and you will see a view like that in Figure 9. Please take notice of the url form in the address.
Figure 9: The first view in our registration application
After populating required data and click button "Next>", you will be navigated to the second step, something like that in Figure 10.
Figure 10: The second step in the registration application
Of course, you can click button "Back<" to return to the previous view to change the data. The last point to notice is in the Final step you can not return to the previous steps any longer. This is easily deduced from the state machine figure.
As hinted at the beginning, this article mainly serves as an elementary material for integrating WF 4.0 into ASP.NET MVC 2.0 Web project development. So, there are still quite a few aspects in the sample application required to be amended. As a strong multithread toolset, the WF 4.0 runtime not only executes your workflows for you, but also provides important services and features support when you write large-scaled complex applications. In this article, however, we've resorted to WF State Machine Activity Pack CTP 1 to provide a state machine implementation. In fact, you can also achieve the same result using the new Flowchart introduced in WF 4.0. Hope this article will lend you a hand.
I'm a college teacher and also a freelance developer and writer from WeiFang China, with more than fourteen years of experience in design, and development of various kinds of products and applications on Windows platform. My expertise is in Visual C++/Basic/C#, SQL Server 2000/2005/2008, PHP+MyS...
This author has published 81 articles on DotNetSlackers. View other articles or the complete profile here.
Please login to rate or to leave a comment.