- Describing Workflow and Workflow Systems
- .NET Framework 3.0 and 3.5
- Overview of WF
- Standard Modeling Activities
- Multiple Workflow Styles
- Hosting
- Tracking
- Rule Capabilities
- Custom Activities
- XAML Workflows and Serialization
- Dynamic Update
- WF and WCF
- SharePoint Workflow
- Designer Rehosting and External Modeling
- Summary
- Installation Instructions
Custom Activities
This section first describes the reason for custom activities and then describes their technical characteristics.
Reason for Custom Activities
You are not limited to the OOB activities in WF. You can create your own. Creating custom activities is as core to WF as any other capability.
This section discusses three reasons to create custom activities: to improve on an OOB activity for usability reasons, to create domain specific activities, and to create custom control flow patterns.
Improve on OOB Activities
In Hour 17, "Learning Advanced Hosting," a third-party created synchronous InvokeWorkflow activity is explored. It is looked at because the OOB InvokeWorkflow activity only calls workflows asynchronously. Many scenarios call for calling workflows and waiting for the called workflow to return a response. Some may even choose to create an entirely new set of OOB activities. Improving the OOB activities is a viable scenario for custom activity development, but is not anticipated to be the primary motivation behind creating custom activities.
Create Domain-Specific Activities
The OOB activities provide general functionality. They are host agnostic and know nothing about any vertical domains or any individual enterprise. Many who use WF will find that its value grows proportionally to the amount of domain activities added. If, for example, you want to use WF to model the credit process, you could use the OOB activities for control flow and then augment them with standard code to perform the actual credit process. Alternatively, you could create Customer, CheckCredit, SendNotification, and other custom activities that augment the credit process. Figure 1.18 shows custom activities on a toolbox, and Figure 1.19 shows the custom Customer activity on a workflow and its properties.
Figure 1.18 CustomActivities toolbox.
Figure 1.19 Customer custom activity on workflow and its properties.
Create Custom Control Flow Patterns
A large portion of WF's utensil and ability to attract a wide range of authors is predicated on there being control flow activities that simplify modeling the respective process. The CAG activity, for instance, makes it possible to model data-driven workflows. The StateMachineWorkflow (workflows are themselves activities) allows for an event-driven style of workflows to be modeled. When nondevelopers are included as authors, there needs to be control flow activities appropriate for them.
Types of Custom Activities
Five types of custom activities exist in WF: basic, long-running, event-driven, control flow, and compound.
Basic activities are similar to standard components. They are called, and then execute, complete their work, and return in a finished state. A sample basic activity is a Customer activity that retrieves customer data. When creating a basic custom activity, you will override its execute method to tell it what to do. You may optionally also customize the activity's appearance, add it to the toolbox, and validate it. The next code snippet shows the code from the custom Customer activity discussed in the last section (variable declarations are omitted for brevity). You will create custom basic activities in Hour 20.
[Designer(typeof(CustomerDesigner), typeof(IDesigner))] [ToolboxBitmap(typeof(Customer), "Resources.Customer.jpg")] public partial class Customer : System.Workflow.ComponentModel.Activity { protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) { // Perform preprocessing. base.RaiseEvent(Customer.InvokingEvent, this, EventArgs.Empty); SqlConnection dbConn = new SqlConnection(ConnectionString); SqlCommand getCustomer = new SqlCommand("GetCustomer", dbConn); getCustomer.CommandType = System.Data.CommandType.StoredProcedure; getCustomer.Parameters.AddWithValue("@CustomerNumber", CustomerNumber); dbConn.Open(); using (SqlDataReader custReader = getCustomer.ExecuteReader(CommandBehavior.CloseConnection)) { if (custReader.Read()) { CustomerName = custReader["CustomerName"].ToString().Trim(); CustomerCreditLimit = double.Parse(custReader["CustomerCreditLimit"].ToString()); CustomerType = custReader["CustomerType"].ToString().Trim(); CustomerYtdSales = double.Parse(custReader["CustomerYtdSales"].ToString()); CustomerHoldRules = custReader["CustomerHoldRules"].ToString().Trim(); } } Console.WriteLine ("The customer number is: " + CustomerNumber); Console.WriteLine ("The customer name is: " + CustomerName); Console.WriteLine ("The customer credit limit is: " + CustomerCreditLimit); Console.WriteLine ("The customer type is: " + CustomerType); Console.WriteLine ("The customer YTD sales is: " + CustomerYtdSales); Console.WriteLine ("The customer hold rules is: " + CustomerHoldRules); return ActivityExecutionStatus.Closed; } }
Following is a summary of the additional custom activity types in WF. These activities build on the steps necessary to create a basic activity.
Long-running activities do not complete on initial call. They continue processing on another thread. They return control to the workflow while the processing occurs. When the processing completes on the other thread, the long-running activity notifies the workflow that it is complete (via WF's internal queuing system). The same Customer activity can also be coded as a long-running activity. The reason is that if the database call to retrieve the customer information was to a local database and was fast, it would make sense to do all work in the execute method. If the call was across the firewall and not so fast, it might be better to return control before the customer data is retuned. Hour 21, "Creating Queued Activities," demonstrates modifying the Customer activity, shown in the previous code listing, that currently executes in one part to execute in two distinct parts.
Event-driven custom activities can wait for external events inside of a Listen or other activity. Custom event-driven activities are described in Hour 22, "Creating Typed Queued and EventDriven-Enabled Activities."
Composite or control flow activities, as previously mentioned, allow you to create your own control flow patterns. These activities are responsible for determining which child activities should execute and then scheduling them for execution. Creating custom composite activities is discussed in Hour 23, "Creating Control Flow Activities Session 1," and Hour 24, "Creating Control Flow Activities Session 2."
A compound activity is prepopulated with other activities. It is useful when a pattern of activities is commonly used. Figure 1.20 demonstrates a CreditCheck compound activity that uses the custom Customer activity to retrieve customer data; then it uses the CheckCredit activity to determine if the customer is on credit hold. Finally, it evaluates the return results in an IfElse activity. The left branch processes the order, and the right branch rejects it. You will create this compound activity in Hour 20.
Figure 1.20 Compound credit check activity.
All noncomposite activities derive (directly or indirectly) from System.Workflow.ComponentModel.Activity. Composite activities all derive from System.Workflow.ComponentModel.CompositeActivity. These are the same classes the BAL activities derive from.
Custom activities are covered in Hours 20 to 24.