I needed to write a customized approval workflow. I know I could use InfoPath to create custom approval task forms, and I saw many posts showing how this is done. But if I could use the SharePoint Approval Workflow task forms, I could save a lot of development time and deployment effort.
This post focuses on how I was able to use the out of the box InfoPath approval approve/reject task forms forms in my custom Visual Studio SharePoint workflow.If you’re looking for a general how-to post on creating SharePoint workflows with Visual Studio, this is not the post for you. I would instead point you to Serge Luca’s excellent 20-part series on creating SharePoint workflows with Visual Studio.
Creating the task
Here’s the skinny on what you need to do in order to use the default Microsoft Office SharePoint Server 2007 (MOSS) approve/reject InfoPath form in a custom Visual Studio workflow.
1. Create a SharePoint workflow project
There are many ways to do this, so I won’t go into details here. My personal favorite way is by using the WSP Builder Visual Studio workflow template project. Just make sure that your workflow class inherits from System.Workflow.Activities.SequentialWorkflowActivity or from System.Workflow.Activities.StateMachineWorkflowActivity.
2. Set the TaskListContentTypeId attribute
Edit the elements.xml file in your workflow feature definition. Set the TaskListContentTypeId attribute value to use the MOSS workflow task content type id:
<Elements>
<Workflow
Name="MyWorkflow"
Description="This is my custom workflow."
…
TaskListContentTypeId="0x01080100C9C9515DE4E24001905074F980F93160"
>
…
</Workflow>
…
</Elements>
3. Add the Task_FormURN and ExtendedStatusColumnValues elements
Continue to edit the elements.xml file in your workflow feature definition. Add the following MetaData element under the Workflow element:
<Elements>
<Workflow …>
<MetaData>
<Task0_FormURN>urn:schemas-microsoft-com:office:infopath:workflow:ReviewRouting-Review:$Subst:LCID;</Task0_FormURN>
<Task1_FormURN>urn:schemas-microsoft-com:office:infopath:workflow:ReviewRouting-Review:$Subst:LCID;</Task1_FormURN>
<Task2_FormURN>urn:schemas-microsoft-com:office:infopath:workflow:ReviewRouting-Review:$Subst:LCID;</Task2_FormURN>
<ExtendedStatusColumnValues>
<StatusColumnValue>$Resources:ReviewFeedback_CanceledStatus</StatusColumnValue>
<StatusColumnValue>$Resources:ReviewFeedback_ApprovedStatus</StatusColumnValue>
<StatusColumnValue>$Resources:ReviewFeedback_RejectedStatus</StatusColumnValue>
</ExtendedStatusColumnValues>
</MetaData>
…
</Workflow>
…
</Elements>
4. Add a CreateTask activity to your workflow
Add a CreateTask activity to your workflow. Make sure to set the TaskType property on the TaskProperties of the CreateTask activity to 1. This will tell the workflow runtime to create the task using the Form Urn corresponding to the inner text in the Task1_FormURN element. The CreateTask activity’s MethodInvoking event is a good place to set the property.
private void createTask1_MethodInvoking(object sender, EventArgs e)
{
//initialize task infrastructure data
this.createTask1_TaskId1 = Guid.NewGuid();
this.createTask1_TaskProperties1 = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
this.createTask1_TaskProperties1.TaskType = 1;
//set task remaining properties
//...
}
Processing a workflow task
Now that you’ve created a workflow task that uses the default approval form, you will want to your workflow to do something useful when a user approves or rejects the task. Here is how to detect when a user approves or rejects the workflow task.
5. Detect task change with OnTaskChanged
This is fairly straight forward: add an OnTaskChanged activity to your workflow. Set the task ID and correlation token to correspond to the ones used when creating the task in the previous section. See Serge Luca’s SharePoint workflow series for details.
6. Task approved or rejected
Here’s the interesting part. Whether a user approves, rejects, reassigns, or requests a change in the task form, the task is always marked as Complete. The actual value that corresponds to what the user selected is stored in the TaskStatus in the ExtendedProperties collection of the SPWorkflowTaskProperties class. The following is a table that correlates the user’s approval action to the value of the TaskStatus extended property:
User Action | TaskStatus Value |
Approve | “#” |
Reject | “@” |
Cancel | [no change] |
Here’s a sample helper method that checks whether a particular workflow task was approved:
public static bool IsTaskApproved(SPWorkflowTaskProperties TaskProperties)
{
return TaskProperties.ExtendedProperties["TaskStatus"] != null
&& TaskProperties.ExtendedProperties["TaskStatus"] as string == "#";
}
Anything else?
That’s it. There is surprisingly little work involved in using the default MOSS approvals forms in your own custom SharePoint Visual Studio workflows, once you know what to look for that is. I’d like to wrap us this post with the benefits to this approach and a few things you should keep in mind when working with the default workflow forms.
Some benefits to this approach
Here are just some of the benefits you get when you reuse the existing MOSS approval task forms rather than creating your own customs InfoPath task forms:
- No InfoPath forms development
- No InfoPath forms deployment
- Out of the box user interface for:
- Approve
- Reject
- Cancel
- Reassign Task
- Request a change
- Instructions to approver
- Capture approver comments
- Out of the box multi-language user interface with appropriate MOSS language packs. Notice the references to “$Resources:”.
A few things you should know
- Any action in default task forms except Cancel marks the task “Complete”. Your workflow must then create a new task with the desired action from the completed task. For example: If a user re-assigns the task to a new user, the task for the user is marked complete. Your workflow must create a new task and assign it to the new user.
- The MOSS task forms derive most of their data from fields in the ExtendedProperties of the task, not the main task properties.
Hello Eugene, thats a Great post. But I'd want to ask you a question. When I do as the posts says, when I test in place of Appear the button Approve/Reject, appears the buttons Send Feecback/Cancel, do you know why is it?? Thanks!
Oriol, I would check to make sure that your Task_FormURN registrations are correct and that you are using the correct TaskType index before you create your task.
hello ,
can u tell me from where can i get the TaskListContentTypeId ?!! please
It is defined in "C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions12TEMPLATEFEATURESOffWFCommonCTypes.xml"
This comment has been removed by the author.
thank u very mutch ^^ !
i have another problem, i deployed the workflow in my website ,when i create an item , its create a TASK ,it's fine !
BUT when i want to edit the task , so to display the approval form , sharepoint give me that message in the middle of the screen :
Can not display this form because session state is not available
This comment has been removed by the author.
The session state error message sounds like it might be a generic InfoPath Forms Services error message. I would try to run an out-of-the-box Approval workflow to ensure that it operates normally before going through your code.
it's Ok ^^ , i should activate System.Web.SessionState.SessionStateModule in the Web.config !
please , the workflow is activated in a list named "biblio" , i want to edit a column value in the concerned item of this list when the workflow is finishied !
Any idea ?!!
workflowProperties.Item will give you access to the list item on which the workflow is currently running.
thaank youuu , it's donne (Y)
hello eugene ,
( Sorry 4 disturbin ) but i have a litte question :
I have a library of document and i added a column named "test"
and i have a webpart that browse files in the library , so i would like to get the value of the column "test" from the SPFile Object
My Code :
….
foreach (SPFile file in folder.Files)
{
fileinfo = new FileInfo();
fileinfo.Name = file.Name;
fileinfo.Size = file.Length / 1024;
fileinfo.URL = file.Url;
fileinfo.IconURL = file.IconUrl;
fileinfo.File = file;
result.Add(fileinfo);
}
Thank's ^^
You should post questions that don't relate to this post on the appropriate Microsoft SharePoint forum. These forums are moderated, so you'll get a response pretty quickly.
http://social.technet.microsoft.com/Forums/en/category/sharepoint
Ok , thanks ^^
Hi Eugene,
Is it possible to make the comments field mandatory conditionally on the OOB task forms.
I want my approvers to provide a comment for sure when they are rejecting the task.
Request your support.
Thanks,
Bhargav
Hi Oru,
I haven't tried it myself, but it should definitely be possible. The fields in the out of the box forms are controlled using the InfoPath forms that ship with SharePoint Server. So, you could at least open up the form in InfoPath designer, and set the Comments field in the data source to be required.
This isn't really best practices as far as customizing SharePoint goes, since you are modifying a file that might get reset in a future service pack or patch. I'm sure we can find a better way given some thought. Let me know what you come up with.
-Eugene
Awesome! Thank you so much!
Hello Eugene,
I am having problem in capturing the comment. Also i want to remove the due by field which is appering on the task form. Can u help me how to do.
Also where will the form be stored to edit it.
Hello Eugene,
Thank you for the post!
Could you please describe me the metadata entries for "2010 Approval task form". Basically I need to replace following entries:
urn:schemas-microsoft-com:office:infopath:workflow:ReviewRouting-Review:$Subst:LCID;
urn:schemas-microsoft-com:office:infopath:workflow:ReviewRouting-Review:$Subst:LCID;
urn:schemas-microsoft-com:office:infopath:workflow:ReviewRouting-Review:$Subst:LCID;
Thank you,
Sam
sams177@gmail.com
Sorry Sam, haven't updated this for 2010 or 2013.
Eugene,
Very helpful article. Thank you so much.
I was looking for it from past two days.
Here when I assign TaskType = 1 I am getting Approve/Reject option and TaskStatus also.
But I am not getting outcome as Approved and completed as 100% when user approves the task.
I want exact Task as getting while assigning task with SharePoint Designer.
How can I get that with VS State Machine Workflow.
Hi Rujal, what version of SharePoint are you trying this with? This article was written for SharePoint 2007, and unfortunately I haven't had time to update it for SharePoint 2010 / 2013 / 2016.
This comment has been removed by the author.
Oh. I am using SharePoint 2013.
Can you please give me suggestion what should I do with this one ?
email : rujal.p.jariwala@trimantra.com
The way I figured out what values corresponded to which workflow task outcome state was by running through an out of the box workflow (like Approval), and then using SharePoint Manager to examine the properties of the Task items in the Workflow Tasks list. That will allow you to see the raw data. You can download SharePoint 2013 Manager here: https://spm.codeplex.com
Hello Eugene,
The approve/reject button works great but I have a bit of a problem displaying the instruction. I tried to set it using
1) task_review_TaskProperties.Description = instruction;
2) task_review_TaskProperties.ExtendedProperties["instructions"] = instruction;
But when I look at the task created the "Task instructions from the workflow owner" is blank while the description did displayed in the description column. Any suggestions ??
Hi Pawadee,
I always like to check the basics first. Make sure that once you've set properties, invoke the .update() method for any SharePoint object you've modified. Also, validate that the incoming data is populated the way you expect it. Writing it out to the workflow history list is a great way to validate all of the data at each step of the workflow.
Good luck.
-Eugene
Hi Eugene,
I did test with task_review_TaskProperties.ExtendedProperties["comments"] = "xxx" and the comments is displayed in the task form but not instruction. So I am a bit wondering if I got the name of the instruction field wrong or something.