Scenario: I have a SharePoint list ‘Knowledge Links’ which is open to all users. I wish to create a simple approval workflow wherein whenever a new ‘Knowledge Link’ is submitted by any user, a task would be created and assigned to a group ‘KT_Approvers’.
An Admin would review the link submitted. If he is satisfied with the link provided, he would mark the link as 100% complete by editing the task created for the same link.
Once the task is marked as 100% complete, the workflow will change the Status of the ‘Knowledge Link’ item as ‘Approved’ and the link can then be used in various views throughout the site. If the task is partially complete, the workflow will set the status to ‘Approval in Progress’.
An Admin would review the link submitted. If he is satisfied with the link provided, he would mark the link as 100% complete by editing the task created for the same link.
Once the task is marked as 100% complete, the workflow will change the Status of the ‘Knowledge Link’ item as ‘Approved’ and the link can then be used in various views throughout the site. If the task is partially complete, the workflow will set the status to ‘Approval in Progress’.
1. Create a WSP Solution. Make sure you select ‘.NET Framework 3.0’
2. Add a ‘State Machine Workflow with Feature’ item to the solution.
Note that Workflow features can be defined only at the site collection (i.e. Scope = Site)
3. The workflow solution requires the following three DLLs as reference which may not be present by default..
4. Add the three workflow DLLs to be required by the solution if they are not present by default.
a. These DLLS can be found at the following location
C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\
b. To be able to refer to these DLLs , the solution should be using the .NET framework 3.0 or above. In other cases, you may find the following error in the workflow designer file.
c. The error can be removed by simply editing the csproj file as follows.
Close the Visual Studio solution currently in use and then Open the .csproj file present in the solution folder (shown below) in Notepad.
Find the following line.
Replace the value inside the
and re-open the solution in Visual Studio.
5. Now, add a new feature (a simple feature with receiver) which will associate this workflow to a list. Also called as Stapling feature. Stapling feature can be kept at the scope Web if required.
6. Remove the following lines from the elements.xml file in the workflow feature.
7. Enter the following code in the Feature Activated event of the Stapling feature.
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPList myList = null; // List to associate workflow to
string myListName = null; // My list name
SPList historyList = null; // Workflow history list
SPList taskList = null; // Workflow tasks list
string workflowTemplateGuid = null; // Workflow template Guid
SPWorkflowTemplate workflowTemplate = null; // Workflow template
SPWorkflowAssociation workflowAssociation = null; // Workflow association
string workflowAssocName = null; // Workflow association name
SPWeb spWeb = SPContext.Current.Web;
myListName = "Knowledge Links";
workflowAssocName = "KTStateMachine";
myList = spWeb.Lists[myListName];
workflowTemplate = spWeb.WorkflowTemplates.GetTemplateByName("KTStateMachine", System.Globalization.CultureInfo.CurrentCulture);
try
{
historyList = spWeb.Lists["KT History"];
}
catch (ArgumentException exc)
{
// Create workflow history list
Guid listGuid = spWeb.Lists.Add("KT History", "", SPListTemplateType.WorkflowHistory);
historyList = spWeb.Lists[listGuid];
historyList.Hidden = true;
historyList.Update();
}
try
{
taskList = spWeb.Lists["Workflow Tasks"];
}
catch (ArgumentException exc)
{
// Create workflow tasks list
Guid listGuid = spWeb.Lists.Add("Workflow Tasks", "", SPListTemplateType.Tasks);
taskList = spWeb.Lists[listGuid];
taskList.Hidden = true;
taskList.Update();
}
// Allow unsafe updates on web
spWeb.AllowUnsafeUpdates = true;
try
{
// Create workflow association
if (null != workflowTemplate)
workflowAssociation = SPWorkflowAssociation.CreateListAssociation(workflowTemplate, workflowAssocName, taskList, historyList);
// Set workflow parameters
workflowAssociation.AllowManual = false;
workflowAssociation.AutoStartCreate = true;
workflowAssociation.AutoStartChange = false;
// Add workflow association to my list
if (null != myList)
{
SPWorkflowAssociation oldAssociation = myList.WorkflowAssociations.GetAssociationByName(workflowAssocName, System.Globalization.CultureInfo.CurrentCulture);
if (null != oldAssociation)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
myList.RemoveWorkflowAssociation(oldAssociation);
});
}
myList.AddWorkflowAssociation(workflowAssociation);
}
// Enable workflow
workflowAssociation.Enabled = true;
}
finally
{
spWeb.AllowUnsafeUpdates = false;
}
}
Verify you made the following changes
a. Enter the correct list name on which the workflow is going to be associated
b. Enter the workflow association name. You can find it in the elements.xml file of the Workflow feature
8. Go to the designer of the workflow created.
9. Rename the event driven activity created by default to ‘InitialStateActivity’
10. Double click on the activity to see the activity design view as shown
11. Rename the first event created by default to onKnowledgeLinkSubmitted
12. In the properties window, besides ‘Invoked’, define a new function ‘onLinkSubmitted_Invoked’ by simply typing the name there and press enter. An event handler will automatically be created. This is the event where you can initialize any class variables you might have created with the properties of the item which triggered this workflow. (E.g. title).
13. Add the code given below in this event.
private void onLinkSubmitted_Invoked(object sender, ExternalDataEventArgs e)
{
title = workflowProperties.Item["Title"].ToString();
}
14. Add a Create Task activity
15. Rename it to createApprovalTask
16. Enter a new correlation token ‘taskToken’. Set its owner activity name to ‘KTStateMachine’
17. Define an event ‘createApprovalTask_Invoked’ for method invoking
18. Bind the Taskid property to a new member (property) by clicking at the button given alongside. Select the options and enter values as shown below later.
19. Similarly, bind the TaskProperties to a new member (field).
20. Enter the following code in ‘createApprovalTask_Invoked’
private void createApprovalTask_Invoked(object sender, EventArgs e)
{
TaskId = Guid.NewGuid();
TaskProperties.TaskType = 1;
TaskProperties.Title = title;
TaskProperties.StartDate = DateTime.Today;
TaskProperties.PercentComplete = 0.0f;
TaskProperties.AssignedTo = "KT_Approvers";
}
21. Go to the designer view and click on the ‘KTStateMachine’ link in the top navigation.
22. Add four more states as shown below and rename them appropriately.
23. Now double click the Initial state Activity and add a Set State activity as shown
24. The workflow should look like this now from the main design view
25. In the State KTLinkTaskFormed, add an activity onKTLinkTaskFormed.
26. Inside this activity, add an onTaskChanged box and set its properties as given below.
27. Bind the AfterProperties to a new property as shown below
Do exactly the same for Before Properties.
28. Set its correlation token to taskToken and Owner Activity Name to KTStateMachine
29. Define the Invoked event ‘onLinkSubmitted_Invoked’
30. Bind the Task ID to the existing member tasked created before
31. The properties should like these
32. Create a IfElse Activity block
33. In the properties of the IfElseBranch Activity , set the properties as shown below
a. The condition isApproved will create a function in code which returns true if that condition is satisfied
b. Do the same for the other IfElseBranch Activity.
34. Add the following code inside isApproved & isRejected function
private void isApproved(object sender, ConditionalEventArgs e)
{
if(onTaskChanged_AfterProperties.PercentComplete == 1.0f)
e.Result = true;
}
private void isRejected(object sender, ConditionalEventArgs e)
{
e.Result = true;
}
35. Under each IfElseBranch activity, add a Set State Activity which will send the workflow to the appropriate state as shown below.
36. Go to the main workflow design view. You should see it as show below.
37. Add two state initiation activities, one each inside KTLinkApproved and KTLinkRejected.
38. Rename them as stateInitializationApproved and stateInitializationRejected
39. Go inside ‘stateInitializationApproved’ activity
a. Add an ‘Update Task’ activity and set its properties as shown
b. Note: The TaskId property here should be bind to the existing member TaskId.
The TaskProperties property here should be bind to a new property ‘updateTaskonApproved_TaskProperties1’ as shown in the figure below.
40. Go inside ‘stateInitializationRejected’ activity and repeat the steps
41. Right Click the ‘KTLinkReviewComplete’ state and set it as completed state.
42. Finally the workflow should look like this.
43. Copy the following code in the update task events generated in the code file
private void updateTaskAfterApproved(object sender, EventArgs e)
{
workflowProperties.Item["Status"] = "Approved";
workflowProperties.Item.Update();
}
private void updateTaskAfterRejected(object sender, EventArgs e)
{
workflowProperties.Item["Status"] = "Approval In Progress";
workflowProperties.Item.Update();
}
44. Build and deploy the solution.
45. Go to the Site collection features and activate the ‘KTStateMachine’ feature.
46. Go to the Site features and activate the ‘StaplingFeature’ .
47. Go to the ‘Knowledge Links’ list in your site.
48. Create a new item as shown below.
49. On creation, we can see the workflow being ‘In Progress’.
50. You will see a workflow task item being created in the ‘Workflow Tasks’ list as shown below.
51. Edit the item, and make its percent complete to 100%.
52. Now go back to the ‘Knowledge Links’ list. The item will have its ‘Status’ column marked as ‘Approved’
53. Note that if the task is changed but not marked as complete, the item will have the ‘Status’ column populated as ‘Approval in Progress’
There are many many more things to explore in SharePoint State Machine workflows. Will update the blog soon......































great rahul and explain it so well and step by step really great
ReplyDeleteGreat man, keep up the good work.
ReplyDeleteGood, how do I assign the task to multiple reviewers. I could not get an answer to this anywhere
ReplyDeleteGlad you liked the post. :)
ReplyDeleteOne way of assigning the task to multiple users would be creating a group of usersand assigning the task to it.
In my example, I assigned the task to a group 'KT_Approvers'
See the line
TaskProperties.AssignedTo = "KT_Approvers";
I believe you are trying to assign the task to many individual users at the same time, which should also be possible without creating a group..
Will check on it and let you know..
Good one :)
ReplyDeleteEven if i approve or reject Task outcome field value is always empty. Any idea why? Thanks
ReplyDeletechak