.NET Tutorials, Forums, Interview Questions And Answers
Welcome :Guest
 
Sign In
Register
 
Win Surprise Gifts!!!
Congratulations!!!


Top 5 Contributors of the Month
david stephan

Home >> Articles >> SharePoint >> Post New Resource Bookmark and Share   

 Subscribe to Articles

Using task-related activities in Sharepoint

Posted By:Manning       Posted Date: February 12, 2011    Points: 75    Category: SharePoint    URL: http://www.dotnetspark.com  

In this article The author explains how to use SharePoint activities for Visual Studio to create, delete, and update tasks.
 

This article is taken from the book SharePoint 2010 Workflows in Action. The author explains how to use SharePoint activities for Visual Studio to create, delete, and update tasks..


G
et 40% off any version of SharePoint 2010 Workflows in Action with the checkout code dnspark40. Offer is only valid through www.manning.com.



In addition to workflows created in SharePoint Designer, Visual Studio workflows offer a similar task processing opportunity. Several SharePoint activities for Visual Studio help to manage tasks in workflows. You can use these activities in your Visual Studio workflows to create, delete, and update tasks. Table 1 shows the complete list of task-related activities. In this chapter, rather than covering all the activities in table 1, we'll cover the most commonly used activities such as those that create and delete tasks and react to events like task modification and deletion.

Table 1 Out-of-the-box task-related activities for Visual Studio

Activity
Description
CompleteTask activity Marks a task as completed
CreateTask activity Creates a default task
CreateTaskWithContentType activity Creates a task off a content type
DeleteTask activity Deletes a task
OnTaskChanged activity Responds to a task's change
OnTaskCreated activity Responds to a task's creation
OnTaskDeleted activity Responds to a task's deletion
RollbackTask activity Rolls back a task to its last accepted state
UpdateAllTasks activity Updates all workflow-associated tasks that are not completed
UpdateTask activity Updates a task's fields through its TaskProperties property

Now that you have a picture of all of the available task activities, let's build an example that puts them to use. The example you'll go through will be the same Capital Expenditure Request workflow that you built in SharePoint Designer but, this time, you'll build it in Visual Studio. This will help you compare the two workflow tools. To get started, create a new Visual Studio sequential workflow project titled CapitalExpenditureRequests. In the project creation wizard, enter the URL to the site containing your capital expenditure requests list, and create a new List workflow with the name Expenditure Requests Approval-VS. Last, associate the new workflow to the capital expenditure requests list.

Create a new custom list called Capital Expenditure Requests. Add two new columns to the list, Request Description as a multiline text field and Dollar Amount as a currency type.

To and have the workflow stop processing in your Visual Studio workflow after the workflow item was changed or deleted, you can use an EventHandlingScope activity paired with the OnTaskDeleted and OnWorkflowItemChanged activities. The EventHandlingScope activity allows you to react to events that fire inside that activity's scope. You'll put the core of your workflow's business logic inside this activity, so each time a task is deleted, for example, your EventHandlingScope activity will capture the event and execute the code. Follow the steps in table 2 to configure these events.

Table 2 Stopping the workflow when the task is deleted or the workflow item is changed

Action
Steps
Result
Set up the EventHandlingScope and two EventDriven activities. 1.  Drop the EventHandlingScope activity onto the workflow Designer surface.
2.  Navigate to the View Event Handlers view of the EventHandlingScope activity by clicking the activity name and, on the dropdown, click the View Event Handlers link.
3.  Drop two EventDriven activities inside the EventHandlers activity that is automatically added for you.
Configure the OnWorkflowItemChanged and SetState activities in the first EventDriven activity. 1.  Drop an OnWorkflowItemChanged activity and set the correlation token property of the activity to workflowToken.
2.  Below the OnWorkflowItemChanged activity, add a SetState activity and set the correlation token of this activity to workflowToken. Rename the activity to setCanceledState1.
NOTE: You can use this activity to set custom workflow states rather than the default In Progress and Completed.
3.  Right-click the setCanceledState1 activity and choose Generate Handlers. You'll fill out the code for this activity later.
The OnWorkflowItemChanged activity will be the first activity inside the EventDriven activity. This will tell the EventDriven activity to wait for the workflow item to change and, if it does, you'll terminate the workflow.
Configure the DeleteTask activity so you won't have any orphaned tasks. 1.  Drop the DeleteTask activity below the SetState activity and set the token to a new token such as TaskToken.
2.  After you set the token to a new token, you'll need to set the OwnerActivityName below the correlation token to Workflow1 by clicking the plus sign next to the CorrelationToken property.
3.  Set the TaskId property of the activity to inform the DeleteTask property which task to delete. Set the property to a new field named TaskId by binding to a new member.

4.  Assign the TaskId to a new GUID by going into the code behind and changing the TaskId field to as follows:
public Guid TaskId = Guid.NewGuid();
Setting the TaskId field properly.
When you first create the TaskId field, it will be set to something like:
public Guid TaskId =
  default(System.Guid);
This will set the TaskId to an empty GUID, for example {00000000-0000-0000-0000-000000000000}. This will cause your workflow to fail because the activities need to be assigned to a GUID.
The DeleteTask activity will now sit below the SetState activity. With this activity in place, your workflow will delete any orphaned tasks when the workflow terminates.
Last, add the terminate activity to stop the workflow. After you've completed these steps, your first EventDriven activity should look like figure 1.



Figure 1 The OnWorkflowItemChanged activity fires whenever the workflow item is changed while the workflow is waiting for request approval.

Now that your workflow is listening for the request to be updated in order to cancel the workflow and delete tasks, you're ready to do the same if the task itself is deleted. If the workflow is waiting for the submission of a task and that task is deleted, you want to ensure your workflow doesn't end up in an orphaned state. In the second EventDriven activity, add a new OnTaskDeleted.
TaskId property and CorrelationToken of the OnTaskDeleted activity

Make sure that the TaskId property of the OnTaskDeleted activity is set to the same field as the DeleteTask activity was set to earlier. All these activities in the capital expenditure request workflow are working off the same activity and their TaskId properties should all be the same. Note as well that the correlation token should be set to TaskToken because that was the token used earlier for the DeleteTask activity.
Add and configure the SetState and Terminate activities as you did for the first EventDriven activity. The correlation token for the SetState activity should be workflowToken as before. There's no point in adding the DeleteTask activity because, by this point, it will have been deleted. Afterwards, your second EventDriven activity should look like figure 2.



Figure 2 Similar to the OnWorkflowItemChanged activity, the OnTaskDeleted activity fires if the task is deleted before it has been approved.
Now that the changed and deleted events are wired up, it's time to add the main business logic into your workflow. You want a task to be created when the workflow is first started. After the task has been created, you want to wait for the approver to approve or reject the request. After the approval or rejection, you set the workflow's status to the corresponding approval. Let's start with the creation of the task and then wait for its approval. Follow the steps in table 3 to configure this part of the workflow.

Table 3 Configuring the workflow to create a new task and wait for its approval


Action
Steps
Result
Drop a Sequence and CreateTask activities inside the EventHandlingScope activity. 1.  Navigate back to the View EventHandling Scope view of the EventHandlingScope activity.
2.  Drop a Sequence activity inside the EvenHandlingScope activity.
3.  Drop a CreateTask activity inside the sequence activity.
The main area of the EventHandlingScope activity will be configured to have a Sequence and a CreateTask activity.
Configure the CreateTask activity. 1.  Set the correlation token to the same token that was used in the DeleteTask and OnTaskDeleted activities. In this case, set it to TaskToken.
NOTE: You should see TaskToken in the dropdown of preexisting token options because TaskToken was defined earlier. If you don't see the TaskToken dropdown option, manually type TaskToken again and set the owner to Workflow1. It is very important to then go back to the EventDriven activities and toggle the correlation token dropdown values of the DeleteTask and OnTaskDeleted activities, because now there will be two TaskToken options in their correlation token dropdowns. All three activities (Create, Delete, and On delete) need to share the same token. Ensure that you never have two tokens in the dropdown that share the same name. They have the same name but not the same ID and are treated as different tokens. If the three activities don't share the same token, the workflow will fail on start.
2.  Set the TaskId property of the activity to the same ID that was used in the DeleteTask and OnTaskDeleted activities.
3.  Bind the TaskProperties property to a new member called TaskProperties. You can use this field to set values of the task like Title, Assigned To, Due Date, and so on.
4.  Right-click the CreateTask activity and choose Generate Handlers. Inside the createTask1_MethodInvoking method, enter the code in listing 1 to set a few of the task's properties before it's created.
The create task activity will now be configured to create the same task that the DeleteTask activity will delete if the workflow item is changed.
Listing 1 createTask1_MethodInvoking
private void createTask1_MethodInvoking(object sender, EventArgs e)
{
  TaskProperties.Title =
  onWorkflowActivated1.WorkflowProperties.Item.Title;
  TaskProperties.Description =
  onWorkflowActivated1.WorkflowProperties.
  Item["Request Description"].ToString();
  TaskProperties.AssignedTo = "philsdevdomain\\pwicklund";
}

Table 3 Configuring the workflow to create a new task and wait for its approval, continued

Action
Steps
Result
Add a while activity below the CreateTask activity, making the workflow keep looping until the task is completed. 1.  Below the CreateTask activity, drop in a while activity.
2.  Change the Condition property of this activity to Code Condition.
3.  Click the plus sign next to the Condition property, and enter a condition method name WhileTaskNotComplete. This will kick you over to the code view of the workflow.
4.  Replace the code in listing 2 with the WhileTaskNotComplete method.
The while activity will be placed below the CreateTask activity. It will be configured to keep looping until the taskComplete field is set to True.

Listing 2 WhileTaskNotComplete

bool taskComplete = false;
private void WhileTaskNotComplete(object sender, ConditionalEventArgs e)
{
  if (taskComplete)
  e.Result = false; // similar to while(0)
  else
  e.Result = true;  // similar to while(1)
}

Table 3 Configure the workflow to create a new task and wait for its approval, continued

Action
Steps
Result
Add an OnTaskChanged activity inside the while activity. 1.  On the designer view of the workflow, drop the OnTaskChanged activity inside the while activity.
This activity will execute each time your task is updated, and the while loop will check if the task has been completed or not. If it has completed, the while loop will finish looping.
2.  Set the correlation token to TaskToken and set the TaskId property to the previously created TaskId field.
3.  Similarly, to binding the TaskId property, bind the BeforeProperties and AfterProperties properties to new members called BeforeProperties and AfterProperties, respectively.
4.  Right-click the OnTaskChanged activity, and click Generate Handlers.
5.  Replace the generated onTaskChanged1_Invoked method with the code in listing 3.
The OnTaskChanged activity will be inside the while activity. It will be configured to wait for the previously created task to be updated. When it is updated, it checks to see if the Status column is set to something other than Not Started.

Listing 3 onTaskChanged1_Invoked

private Guid statusColumnId =
  new Guid("{c15b34c3-ce7d-490a-b133-3f4de8801b76}");
private string status = "";
private void onTaskChanged1_Invoked(object sender, ExternalDataEventArgs e)
{
  status = AfterProperties.ExtendedProperties[statusColumnId].ToString();
  if (status == "Not Started")
  taskComplete = false;
  else
  taskComplete = true;
}

How the ExtendedProperties property works


The TaskProperties property contains many of the task's common fields such as Title, DueDate, and Description. For a few default columns like Status and any custom columns, ExtendedProperties must be used. ExtendedProperties is a hash that contains the rest of the default columns, such as Status, as well as any custom columns you may have added to the list yourself or through a content type. The interesting thing about this is that the default columns are entered in the hash through a unique ID-their GUID-whereas custom columns are entered with their column name.

Figure 3 shows how to get the field ID with PowerShell if you want to retrieve a default column from the extended properties hash.



Figure 3 The default ExtendedProperties can be retrieved from the hash through their unique ID. You can use PowerShell to get this ID.


With these steps in place, your while activity will stop looping when the Status column is changed to something other than Not Started. Now you add an IfElse activity to determine what to set the workflow's status to. If the status in the task is set to Approved, set the workflow's status to Approved. If the status in the task is set to Deferred, set the workflow's status to Deferred, and so on (see table 4).

NOTE

By default, the Approved and Rejected statuses are not in the status column.
In the tasks list, edit the Status column and enter the statuses shown in figure 4.



Figure 4 By default, a task doesn't have your statuses in the Status column, and you'll need to modify the column to include your statuses.

Table 4 Configure an IfElse activity to determine whether the status is Approved or Deferred

Action
Steps
Result
Add an IfElse activity with three branches. 1.  Drop the IfElse activity below the EventHandlingScope activity.
2.  Right-click the IfElse activity, and click Add Branch to add a third branch into the activity.
A new IfElse activity will be below the EventHandlingScope activity.
Add a code condition to the first branch to determine if the status was Approved. If it was approved, set the state of the workflow to be Approved. 1.  For the first branch, edit the Condition property and specify Code Condition.
2.  Click the plus sign and type the condition method as IsApproved.
3.  In the IsApproved method that was generated , enter the following code:
if (status == "Approved")
  e.Result = true;
else
  e.Result = false;
4.  Add a SetState activity into the first branch and rename it to setApprovedState.
The first branch in the IfElse activity will check to see if the status is set to Approved. If so, the first branch will execute; otherwise, it will move on to the second branch.
Add a code condition to the second branch to determine if the status was Deferred. If it was deferred, set the state of the workflow to be Deferred. 1.  For the second branch, edit the Condition property and specify Code Condition.
2.  Click the plus sign and type the condition method as IsDeferred.
3.  In the generated IsDeferred method, enter the following code:
If (status == "Deferred")
  e.Result = true;
else
  e.Result = false;
4.  Add a SetState activity into the second branch and rename it setDeferredState.
The second branch in the IfElse activity will check to see if the status is set to Deferred. If so, the second branch will execute; otherwise, it will move on to the third branch.
Add a SetState activity into the third branch and rename it to setRejectedState. NOTE: If the first branch returns False and the second branch returns false, the activities in the third branch will execute
Give each of the three SetState activities a correlation token of workflowToken. Right-click each and choose Generate Handlers. Afterwards, the red exclamation point on each of the Set State activities will disappear, and each will have a method that can be used to set the state.

At this point, your workflow is nearly complete. All that's left is to fill out the handlers for the five SetState activities. Before you do that, confirm that your workflow Designer surface looks something like figure 5.



Figure 5 Your workflow Designer surface should look like this after you have all the activities configured.


To be more consistent with the SharePoint Designer workflow we created, we would need to add a few sendEmail activities to send out the notifications.

The first step to setting up your custom workflow statuses is to define those statuses in the workflow's Elements.xml file. Any custom statuses need to be defined in this XML file, inside the MetaData element. The statuses live inside the child element called ExtendedStatusColumnValues, with each status inside a StatusColumnValue tag. Open the Workflow1's Elements.xml file and define your extended status values as shown in figure 6.


Figure 6 Custom workflow statuses need to be defined in the workflow's Elements.xml file.

Each SetState activity has a property called State. This corresponds to an integer value that determines what state to set the workflow's status to. There are 15 states by default so you can set this property to a number from 1 to 15, and you'll set your workflow's status to one of those out-of-the-box states. Table 5 shows the object model's current values for these states.

Table 5 Ten workflow states are defined in the SPWorkflowStatus enum, with a Max value set to 15.


State (SPWorkflowStatus enum)
Value
Completed 5
ErrorOccurred 3
ErrorOccurredRetrying 7
FailedOnStart 1
FailedOnStartRetrying 6
InProgress 2
Max 15
NotStarted 0
StoppedByUser 4
ViewQueryOverflow 8

To set the workflow to one of your custom states, you need to set it to 16 or higher. For example, if you set it to 16, you'd set the workflow's status to Approved. If you set it to 19, the workflow's status would be Canceled. Rather than hard-coding a value in the State property, it's better to do this is through code. Through code, you can use the SPWorkflowStatus.Max property, which will protect you if Microsoft ever changes the state Max from 15 to, say, 16, which would throw your status values off and might even break your workflow. To do this, configure your SetState handlers similarly to those in listing 4.

Listing 4 Handlers for the SetState activities

enum CustomStates  #1
{
  Approved = 0,
  Rejected,
  Deferred,
  Canceled
};

private void setCanceledState_MethodInvoking(object sender, EventArgs e)
{
  ((SetState)sender).State = (Int32)SPWorkflowStatus.Max +  #2
  (Int32)CustomStates.Canceled;
}

private void setApprovedState_MethodInvoking(object sender, EventArgs e)
{
  ((SetState)sender).State = (Int32)SPWorkflowStatus.Max +
  (Int32)CustomStates.Approved;
}

private void setDeferredState_MethodInvoking(object sender, EventArgs e)
{
  ((SetState)sender).State = (Int32)SPWorkflowStatus.Max +
  (Int32)CustomStates.Deferred;
}

private void setRejectedState_MethodInvoking(object sender, EventArgs e)
{
  ((SetState)sender).State = (Int32)SPWorkflowStatus.Max +
  (Int32)CustomStates.Rejected;
}

#1 Refactor status integer into enum
#2 Add Max value to custom status

As you can see, you're using an enum #1 to set your custom state integers. Then, in each handler, you're adding the Max value to your enum's integer value #2, calculating the state to set the workflow's status to.

After you have this code entered, build your project and deploy it into SharePoint. Next, create a new expenditure request and run this new workflow on that request. You should notice the workflow sitting in the In Progress state and a new task created in the tasks list. Edit the Status column on that task by changing it to a state other than Not Started. Then on the Capital Expenditure Requests list, the Visual Studio workflow's status column should correspond to the status that was selected in the task (figure 7).



Figure 7 After the task is deferred, the workflow's status column is updated just as in the SharePoint Designer workflow.

Summary


When building Visual Studio workflows that need to perform task processing, you'll find a host of task-related activities you can use. Activities such as the CreateTask and OnTaskChanged activities allow you to create a new task and wait for that task to be completed. Other tasks such as the DeleteTask and OnTaskDeleted are commonly used as well.


SharePoint 2010 Workflows in Action
EARLY ACCESS EDITION

Phil Wicklund
MEAP Release: May 2010
Softbound print: December 2010 (est.) | 400 pages
ISBN: 9781935182719


 Subscribe to Articles

     

Further Readings:

Responses

No response found. Be the first to respond this post

Post Comment

You must Sign In To post reply
Find More Articles on C#, ASP.Net, Vb.Net, SQL Server and more Here

Hall of Fame    Twitter   Terms of Service    Privacy Policy    Contact Us    Archives   Tell A Friend