UPDATE 02/01/2012:
The post went live on MSDN today! I am beyond excited about getting a sanctioned MSDN article posted and have lots of people to thank which I will do in a separate post.
Here it is:
http://msdn.microsoft.com/en-us/library/hh824675.aspx
NOTE TO READERS: This article is scheduled to be published on MSDN very soon, when it goes live I will cross link it here, until then, enjoy! -a2s.
| Summary: |
Learn how to programmatically create and test a SharePoint sequential workflow and use a custom field on the workflow tasks. The sequential workflow will not proceed until a field on the list item has been completed in a specific manner, and the custom approval field on the task has been set correctly. |
| Applies To: |
Microsoft SharePoint 2010, Microsoft Visual Studio 2010 |
| Published: |
January 2012 |
| Provided By: |
Justin Joyce, LANtek Computer Services (http://lantekcomputer.com) |
Contents
- Introduction to Sequential Workflows
- Creating a New Site Collection
- Creating the Columns and Content Types
- Creating the SharePoint Sequential Workflow in Visual Studio
- Testing the Sequential Workflow
- Conclusion
- Additional Resources
Introduction to Sequential Workflows
SharePoint sequential workflows developed in Microsoft Visual Studio 2010 enable you to create powerful tools for streamlining business processes and task approvals. A key component to designing an effective and efficient workflow is to align it as closely as possible to the business process it is augmenting, both in logical function and user experience interaction. Central to this is the use of language and input validation that accurately reflects the progressive routine and meets the expectations of the end users.
To illustrate this type of functionality, this article demonstrates creating a SharePoint sequential workflow in Visual Studio that stops task completion until the text in a list item field exceeds 100 characters. In addition, the workflow leverages a custom approval field on the workflow task. Instead of the standard Not Started or Completed or In Progress text contained in the out of the box Status field, the task adds a Business Approval field containing either I Approve or I Do NOT Approve. The workflow programmatically sets the Status field to Completed when the item and task meet the required criteria. If the description field is not filled in properly, the task is reverted to the In Progress status and the workflow logs to the history list that a required field is missing.
Creating a New Site Collection
In the following steps, you create a new site collection.
Note: For more detailed instructions you may also reference the following TechNet article:
http://technet.microsoft.com/en-us/library/cc263094.aspx
To create the new site collection
- Open Central Administration on your SharePoint server and then click the Application Management link located in the left navigation pane. This displays the Application Management home page.
- Undering Site Collections, click Create Site Collections.
- In the Create Site Collections page, ensure that the yellow box in the upper right hand corner of the page (below the OK and Cancel buttons) displays the name of the new Web Application created in Step 1.
- When the correct Web Application is selected, type in a title. You may leave the description field blank if desired.
- For the Web Site Address,select a valid address and record it for later use in the Visual Studio project. An example of a valid address is http://servername:port/.
- Under the Template Selection area, in the Select a template box, click the Publishing tab and then click the option labeled Publishing Portal.Figure 1 shows the Select a template box.
Figure 1 Choosing the site template.
While other site template types can be used, the publishing portal comes with the Workflow Tasks list already provisioned. If your instance of SharePoint does not have the Publishing Portal template available, you can use a Team Site template and provision the Workflow Tasks list at a later point in this article.
Under the Primary Site Collection Administrator box, type the Active Directory account name of the primary site collection administrator. If desired, also type a secondary site collection administrator in the next box. Leave the Quota Template option set to No Quota.
When you have verified that all options are correct you may proceed to press OK.
Creating the Columns and Content Types
In the following steps, you create the custom columns, content types, custom list, and workflow task list.
To create the custom columns
- Navigate to the newly created site collection and ensure that the site is up and running.
- When the site has loaded, click the Site Actions menu in the upper left corner and then click Site Settings.
- Under the Galleries heading, click Site Columns.
- In the upper left hand corner of the Site Columns page , click Create to create a new choice column named Business Approval.
- Format this column as a drop down list, containing the following values:
- Undecided (Default)
- I Approve
- I Do NOT Approve
Leave the default value as Undecided (Default), the group as Custom Columns, and the description field blank.
- Next, create another site column to act as the description field that is required to be filled in for the workflow to progress. Name the field Request Description and format it to be a multi-line plain text field.
- To provide better clarity to the end user, type a description into this field stating that it should be longer than 100 characters.
- Now that the supporting fields have been created, you need to making two content types for use during the workflow progression. On the “Site Actions” menu, click Site Settings.
- Under the Galleries section, click Site content types.
- Click Create in the upper left hand corner of the page to make a new content type called Initial Request.
- Under the Parent Content Type section, select the parent content type from the List Content Types. Set the Parent Content Type to Item as shown in Figure 2:
To create the custom content types.
Figure 2 Creating a new content type
- In the Put this site content type into section, select Custom Content Types, and then click OK.. This takes you to the content type management screen.
- Click the Add from existing site columns option to enable you to add the Request Description field to the Initial Request content type.
- When the Request Description text has been added, click on its title under the Columns heading on the content type management screen. The Change Content Type Column screen is displayed where you can set the column as Hidden as shown in Figure 3.
Figure 3 Marking the column as hidden
Using the previous steps, create a second content type named Request and ensure that it contains the same fields with the exception that the Request Description is required.
Additionally, instead of using Item as the parent content type, select Initial Request. Because the Request Description column is validated via the workflow, make it a required field to provide more clarity to the end user.
In the next steps, you create a custom list to hold the two request content types and act as the target for the sequential workflow.
To create the custom list
- Return to the Site Actions menu and then select View All Site Content.
- Click Create in the upper left hand corner of the page to launch the Create dialog.
- Locate the Custom List template (see Figure 4) and name it Requests.
Figure 4 Finding the custom list template
- When the list is created, add your custom content types to it by selecting the List Settings button from the ribbon, and then under the “General Settings” section, click Advanced Settings.
- Set the Allow Management of Content Types option to Yes and then save your changes by clicking OK.
- To add your request content types to the list, under the “Content Types” section, click Add from existing site content types link. Locate both of the Initial Request and Request content types and add them. Click OK to save your changes.
- Under the Content Types section, click the Item type and then click Delete this content type to remove it from your list. This leaves only your two custom content types.
- Finally, click Change new button order and default content type and unselect the Visible box next to your Request content type as shown in Figure 5. This ensures that end users are restricted to creating only the Initial Request type when adding new list items.
Figure 5 Setting the default content type for the list
In the next steps, you create a workflow task list. If you chose to use a template other than Publishing Portal, you are required to create a Workflow Tasks list on your site. If you are using the Publishing Portal template, you can continue on to the section Creating the SharePoint Sequential Workflow in Visual Studio.
To create the Workflow Tasks list
- Return to the Site Actions menu and then select View All Site Content.
- Click Create in the upper left hand corner of the page and then locate the Tasks template as seen in Figure 6.
- Name the new listWorkflow Tasks and then click Create in the right hand column (see Figure 7).
Figure 6 Find the Tasks list template
Figure 7 Naming and creating the Workflow Tasks list
Creating the SharePoint Sequential Workflow in Visual Studio
In the following steps, you create a sequential workflow project in Visual Studio, and then add events and other properties to the workflow.
To create a Visual Studio SharePoint sequential workflow project
- Start Visual Studio 2010 and select New Project in the left hand column of the start page.
- In the Visual C# section, in the Installed Templates tree, select SharePoint.
- In the project type list, choose Sequential Workflow.
- Create a new directory for the solution and name it CustomTaskApproval as shown in Figure 8.
Figure 8 Creating a new SharePoint Sequential Workflow project in Visual Studio
After the project is created, the SharePoint Customization Wizard is displayed. In the first dialog screen, use the URL of the new site collection you created previously as the local site for debugging. Ensure that the solution is set to be deployed as a farm solution (see Figure 9), and then click Next.
Figure 9 Starting the SharePoint Customization Wizard
On the next page of the SharePoint Configuration Wizard, type the name of the workflow – in this case, use CustomTaskApproval – Workflow1 as shown in Figure 10.
Next, choose List Workflow for your template type and then clickNext.
Figure 10 Choosing the workflow name and type
On the next SharePoint Customization Wizard screen, Visual Studio automatically associates the workflow with the Requests list (see Figure 11). Leave the default values for the history and task lists.
Figure 11 Setting up the target list and task and history lists for the workflow
On the final configuration screen, ensure that only the The workflow starts automatically when an item is created option is selected as shown in Figure 12.
Figure 12 Selecting the workflow start options
With the workflow set up complete, begin adding the events and associated code.
To add activities and code to the sequential workflow
Note: By default, Visual Studio adds the onWorkflowActivated1 event to the design surface. This event is not utilized for this example; however, it can be left on the design surface.
From the Toolbox, drag the following activities onto the design surface:
- Code – Name this activity InitializeItem. The Code Activity is responsible for changes and checks of the item on its initial entry into the workflow.
- CreateTask – Name this activity createRequestTask. CreateTask is responsible for setting some of the properties on the initial creation of the task such as the description, to which person the task has been assigned, and so forth.
- While – This While activity contains another activity that watches for the task to change. It is contingent upon a code condition (more on this later).
- OnTaskChanged – Name this activity onRequestTaskChanged. The task changed activity is responsible for monitoring the task and ensuring any changes that the user makes to the task meet the validation rules. In this case, a description containing over 100 characters on the item and the task’s custom approval field set correctly.
- CompleteTask – Name this activity completeRequestTask. Place this activity directly after the While activity. This activity is responsible for handling the actual completion of the task; that is, setting the out-of-the-box status field to Completed.
With all the activities in place, the design surface should now look like Figure 13:
Figure 13 Workflow activities on the design surface
Before the project will be able to properly build, you need to set up the public properties and correlation tokens, associating them to the events on the design surface through the properties pane.
To create properties for the activities and binding correlation tokens
The properties need to be created in the code-behind first, as follows:
public Guid workflowId = default(System.Guid);
public SPWorkflowActivationProperties workflowProperties = new SPWorkflowActivationProperties();
// these properties are for the workflow task that will be created.
public SPWorkflowTaskProperties RequestTaskProperties = new SPWorkflowTaskProperties();
public SPWorkflowTaskProperties RequestTaskBeforeProperties = new SPWorkflowTaskProperties();
public Guid RequestApproveTaskId = default(Guid);
public int RequestApproveTaskItemId;
public bool RequestApproveComplete = false;
To begin associating the correlation tokens with their corresponding activities, perform the following steps:
- For the onWorkflowActivated1 activity, create a new correlation token named workflowToken. Set the owner activity for this correlation token to Workflow1. In a larger scenario, this token would be used for many more activities and events on the design surface but, for this exercise, it is only be used on this activity. The task activities require their own correlation token shared between them to ensure that they are working on the same task.
- For the createRequestTask,onRequestTaskChanged, and completeRequestTask activitie,s create a correlation token named RequestTaskToken with an OwnerActivity of Workflow1. You can create this by typing it into the CorrelationToken box on the property pane for the first task event and then selecting it for the other activities.
Figure 14 shows what the properties pane for the createRequestTask activity looks like.
Figure 14 Setting the activity properties

- Assign the correct public members from the code-behind to the ListItemId, TaskId, and TaskProperties fields by clicking on the activity on the design surface and then selecting the property name from the Properties pane. Using the ellipses (…), select the member from the Bind to an existing member tab, and then click OK.
This will need to be done for each task activity on the design surface in order to ensure that they all have the same correlation token and the public members assigned correctly. The public members differ slightly for each of the task events. For example, onRequestTaskChanged add a BeforeProperties attribute and completeRequestTask only requires the TaskId.
Figure 15 Binding the activity property to an existing member

Now that all correlation tokens and properties are set accordingly, begin to generate the associated methods.
To generate method signatures and add the code
- Double click each of the activities on the design surface. Visual Studio automatically displays the code and generates the method signature required for each activity. The exception to this is the While activity – this method will need to be created manually.
- Create the associated method for the While activity by adding the following code:
private void notRequestTaskApproved(object sender, ConditionalEventArgs e)
{
e.Result = !RequestApproveComplete;
}
In the properties pane for the While activity, set the Condition attribute to Code Condition and the Condition attribute contained under it to notRequestTaskApproved as shown in Figure 16. This will cause the While activity to continue looping until the method returns the appropriate response.
Figure 16 Setting up the Code Condition property for the whileActivity

- Next, add the following two helper methods:
private void ResestTask(SPListItem task, SPListItem currentItem, string message)
{
LogComment(message + currentItem.Title);
// This line is very important. It keeps you from receiving the error "this task is currently locked by a running workflow."
task[SPBuiltInFieldId.WorkflowVersion] = 1;
task["Status"] = "In Progress";
task["Business Approval"] = "Undecided";
task.Update();
}
private void LogComment(string logMessage)
{
SPWorkflow.CreateHistoryEvent(workflowProperties.Web, this.WorkflowInstanceId, 0, workflowProperties.Web.CurrentUser, new TimeSpan(), "Update", logMessage, string.Empty);
}
The first helper method, ResetTask, is called only when a task needs to be reverted to an In Progress state, such as when a user attempts to complete it before filling in the required description field on the list item. This rollback method is required for the workflow solution to prevent the This task is currently locked by a running workflow error that occurs when a task is rolled back to In Progress via code, if a user tries to change it again later. This error message is related to the workflow version on the task item; hence, explicitly setting the Workflow version property to 1.
The second method is a simple logging function that enters updates to the Workflow History list.
With the setup of the workflow project in place, you can begin filling in the logic for the associated methods in the code behind file.
- Add the following code to the InitializeItem_ExecuteCode method:
private void InitializeItem_ExecuteCode(object sender, EventArgs e)
{
// Change the content type from Initial Request,
// to just Request.
// This flips it over to having the Request Description as a required field.
SPListItem currentItem = workflowProperties.Item;
currentItem["ContentTypeId"] = workflowProperties.List.ContentTypes["Request"].Id;
currentItem.Update();
}
When a request is entered, it is picked up by the workflow upon item creation. With the list set to only allow users to enter requests with the content type of Initial Request, the workflow can now change the item’s content type to Request. Changing the item to the Request type enables the Request Description field to display on the edit form as a required field.
- Next, add the following code to the createRequestTask_MethodInvoking method. This is where you will set up all the applicable properties for the workflow task.
private void createRequestTask_MethodInvoking(object sender, EventArgs e)
{
// Now create the approval task.
SPListItem currentItem = workflowProperties.Item;
// Set up some of the properties.
RequestApproveTaskId = Guid.NewGuid();
RequestTaskProperties.Title = workflowProperties.Item["Title"].ToString() + " is ready for review";
RequestTaskProperties.Description = "Please review the request and ensure it is valid. If it is valid, then please select 'I Approve' on this task and save it.";
LogComment("Request Task Created.");
}
- Finally, add the following code into the onRequestTaskChanged_Invoked method.
private void onRequestTaskChanged_Invoked(object sender, ExternalDataEventArgs e)
{
int tid = onRequestTaskChanged.AfterProperties.TaskItemId;
SPListItem task = workflowProperties.Web.Lists["Workflow Tasks"] .GetItemById(RequestApproveTaskItemId);
SPListItem currentItem = workflowProperties.Item;
try
{
// Check to make sure the field is there on the item.
if (task["Business Approval"] != null && currentItem["Request Description"] != null)
{
// Evaluate the value of the field.
if (task["Business Approval"].ToString() == "I Approve" || task["Business Approval"].ToString() == "I Do NOT Approve")
{
if (currentItem["Request Description"].ToString().Length >= 100)
{
RequestApproveComplete = true;
}
else
{
RequestApproveComplete = false;
ResestTask(task, currentItem, "Request Description is not long enough.");
}
}
else
{
RequestApproveComplete = false;
ResestTask(task, currentItem, "Business Approval is not set.");
}
}
else
{
// This should never happen because there is a default, but always good just in case.
RequestApproveComplete = false;
ResestTask(task, currentItem, "Business Approval status is null or no Request Description.");
}
}
catch (Exception ex)
{
RequestApproveComplete = false;
ResestTask(task, currentItem, "Exception.");
LogComment(ex.ToString());
}
}
This method evaluates the Request item, ensures that the Request Description field is properly filled in, and that the associated workflow task has been marked with the correct status code.
If all criteria are met, RequestApproveComplete will return True, causing the While activity to exit.
Finally, add the following code to the completeRequestTaskApproved activity:
private void completeRequestTask_MethodInvoking(object sender, EventArgs e)
{
// Grab the task item so the workflow can complete it.
SPListItem task = workflowProperties.Web.Lists["Workflow Tasks"] .GetItemById(RequestApproveTaskItemId);
// This line is very important. It keeps you from receiving the error "this task is currently locked by a running workflow."
task[SPBuiltInFieldId.WorkflowVersion] = 1;
task["Status"] = "Completed";
task.SystemUpdate(false);
SPListItem currentItem = workflowProperties.Item;
if (task["Business Approval"].ToString() == "I Do NOT Approve")
{
string currentTitle = workflowProperties.Item["Title"].ToString();
workflowProperties.Item["Title"] = "DECLINED: " + currentTitle;
workflowProperties.Item.Update();
}
else
{
string currentTitle = workflowProperties.Item["Title"].ToString();
workflowProperties.Item["Title"] = "APPROVED: " + currentTitle;
workflowProperties.Item.Update();
}
}
Again, you are setting the workflow version to keep the task from being locked when the update is performed from the code. The workflow sets the out-of-the-box Status field to Completed, which ends the task. A quick evaluation is then performed on the state of the task (approved or declined), and the item is updated accordingly to reflect the decision.
The final step in this process is the configuration of the custom Business Approval field on the Workflow Task content type.
To perfrom the final site configuration for the custom task approval field
- Before you are able to edit the fields associated with the Workflow Task, it needs to be added to the Workflow Tasks list. On the Debug menu in Visual Studio, select Start Debugging, or press F5 as shown in Figure 17. This launches a new browser window and attaches the debugger to the w3wp process.
Figure 17 Starting the workflow in debug mode

- When the site has loaded, go to the requests list and then create a new item. This causes the Workflow Task content type to be automatically added to the Workflow Tasks list. To verify this, onthe Site Actions menu, select View All Site Content. Select the Workflow Tasks list and then click the List Settings button.
On the List Settings page, you see the Workflow Task content type in the list of content types as shown in Figure 18.
Figure 18 Viewing the content types on the Workflow Tasks list.

- Click the Task content type and use the Delete this content type option to remove it from the Workflow Tasks list. Repeat this procedure with the Summary Task content type.
- Now, click the Workflow Task content type to go to the settings page.
- Click the Status field and then change its Column Settings from Optional to Hidden. Click OK to save the changes.
- On the settings page for the “Workflow Task” content type, under the Columns section, click Add from existing site or list columns .
- Locate the Business Approval column in the list and then double click it to move it over to the Columns to add list (see Figure 19). Click OK to save the changes.
Figure 19 Adding custom columns to the Workflow Task content type.

Testing the Sequential Workflow
In this section, you test the workflow. You do this by creating a new request and then updating the request to see the results.
To create a new request item, go to your Requests list and click the Add new item link in the lower left hand corner of the list view. The New Item dialog will launch as shown in Figure 20.
Figure 20 New item screen for the requests list

Enter a title for the request and click the Save button.
The associated task is created by the workflow in the Workflow Tasks list. To view the task go to the Site Actions menu, select View All Site Content, and select the Workflow Tasks list from under the Lists heading. The task will display at the top of the main view as pictured in Figure 21.
Figure 21 List view of the newly created task

Click on the Title of the task to display the full task form. Use the Edit button in the top left hand corner of the form to place the task in edit mode (Figure 22).
Figure 22 Workflow Task edit form with custom approval field

Clicking the save button with the “Undecided” value still in the “Business Approval” field causes the OOTB “Status” field to be set to “In Progress” and logs the following into the workflow history (see Figure 23):
Figure 23 Viewing the Workflow History list

Likewise, if you omit the “Request Description” field on the list item while trying to approve or decline the task, the “Status” field will be set to “In Progress.”
Now, go back to your Request item and edit it. You will see that the “Request Description” field is now showing and required. Fill it in with some value over 100 characters (Figure 24) and save your changes, then you may approve or decline the task.
Figure 24 Request list item edit form

Now that the Request item is properly filled in go back to your Workflow Task list, edit the task associated to the Request item, and choose I Do NOT Approve from the Business Approval field. This causes the workflow to set the Status field to Completed as seen in Figure 25.
Figure 25 View of the completed (and rejected) task in the Workflow Task list

You can see the change in the title for the Request item in Figure 26:
Figure 26 Title change performed by the workflow on a rejected task

If the workflow task were to be approved the title of the Request item is altered to reflect the approval action (see Figure 27):
Figure 27 Title change performed by the workflow on an approved task

Conclusion
Often the needs of the business process you are working with will require a more flexible solution that better aligns to the operation than is provided from the out-of-the-box functionality. In these cases, it is very advantageous to create your own custom approval and validation criteria for tasks in SharePoint sequential workflows. Expanding upon these techniques provides a powerful mechanism to enforce business rules and integrate efficiently with existing logical processes.
Additional Resources
Find more information about the topics described in this article at the following locations.