How To: Use default SharePoint approve/reject InfoPath task form in custom Visual Studio workflows
Editor’s Note: In a new series of articles, I will be introducing you to some of the speakers who will be presenting at the SharePoint Evolutions Conference in London next month, pointing you to articles on their sites, offering downloads of white papers, and publishing articles on their subjects of expertise. — Mark Miller
Eugene Rosenfeld
Things that Should be Easy
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.
Guest Author: Eugene Rosenfeld
Things that Should be Easy
Eugene Rosenfeld is the CTO of Black Blade Associates. He started his IT career as a database programmer and soon moved into enterprise application integration (EAI) and portal systems. Eugene holds a strong belief that all systems should have the innate ability to intelligently communicate with one another. Most recently he has been heavily involved with distributed systems architecture, Services Oriented Architected (SOA), peer-to-peer systems, and cloud computing.
Eugene has been recognized for his community involvement by Microsoft through their prestigious MVP program. His MVP profile is available at https://mvp.support.microsoft.com/profile/Eugene.Rosenfeld.
Hi Eugene,
I followed your steps. When i started the workflow I am getting Failed on Start (retrying) error. I tried to debug the workflow but it does not break any where while creating the Workflow task.
Please let me know if I am missing anything..
Thanks,
Veera.
Veera,
If the workflow does not start, you will never hit a breakpoint. Unfortunately the Failed on Start (retrying) is SharePoint workflow’s catch-all error message. It could mean anything. The best place to check for clues as the nature of the error is in SharePoint’s ULS logs. They are text files located in:
%Program Files%\Common Files\Microsoft Shared\web server extensions\12\LOGS
Search for text such as “error” or ” at” to quickly get to the error messages.
-Eugene
I gave this a try and managed to get it working. However, I noticed that contributors can approve their own work. I have checked all the permissions and this should not be occurring.
Ben, you could try adding a code activity to your workflow after the CreateTask activity to set custom permissions on the task that just got created. This will let you apply very granular rules as to who is able to modify which workflow tasks.
-Eugene
This is a fantastic sample. I got it working in just a few minutes time. However, I didn’t follow how to handle the “reassign task”. Is there a sample somewhere you can point me to? How do I know the user hit the “reassign task” button?
The re-assign task doesn’t work quite as you might expect. Rather than assigning the current task to a new person, re-assign task actually completes the current task with a specific TaskStatus, then creates a new task for the new person and copies the data from the current task to the new task. I don’t know what the TaskStatus for task re-assignment is, but you can find out the same way I did: Start an approval workflow, reassign a task, then inspect its properties using a tool like SharePoint Manager:
http://spm.codeplex.com/
http://weblogs.asp.net/gunnarpeipman/archive/2009/03/11/sharepoint-manager-2007.aspx
-Eugene
hi Eugene,
i still not understand how build U Reassign A task with reassign task?
i mean how u Design u ur workflow activity ?
can u send me some code?
Mario — where you ever able to figure out how to determine if a Reassign or RequestChange was triggered? I’m having the same issue and as best I can tell neither Reassign nor RequestChange update the “TaskStatus” property with anything. Is that what you found? How (if at all) did you resolve this?
Thanks
rene
Hi,
Did you get the answer for you r question?
Even i have a question in retrieving reassign task and change request values in the workflow.
Any help is appreciated.
can this be applied in workflow created by sharepoint designer ?
That’s a great question. As far as I can tell, SharePoint Designer does not leverage InfoPath Web Forms technology for its workflow forms. I assume the reason is that SharePoint Designer needs to work with WSS and InfoPath Web Forms are only part of MOSS.
Sorry for not responding to comments. Ramya’s comment was the first one that sent me an email notification. I will respond to comments shortly.
-Eugene
hi Eugene,
i have problem if i want to build custom workflow Reassign Task. could u show me how to do that,
when we use approver – sharepoint 2010 and click reassing task, current task will be completed and the new task will be create.
how to do that in custome workflow???
Hi Taufan,
As with just about everything you do in custom Visual Studio workflows, you will need to resort to code to have your workflow mimic the same reassign task behavior as the SharePoint workflows. When the initial task is completed, you will need to check its status. If you detect the ExtendedProperties["TaskStatus"] as string is a Reassign code, you will manually need to create a new task, assign it to the correct person, transfer the title, body, and other task properties, and then check the ExtendedProperties["TaskStatus"] as string of the new task you just created to see the result. You will have to continuously repeat this process until the ExtendedProperties[TaskStatus] as string is the code for either Approved or Rejected.
I know its cumbersome, but this is the way the OOTB MOSS workflow forms operate. The easiest way to continuously check the ExtendedProperties[TaskStatus] property in a Sequential workflow is with a loop activity. A State Machine workflow might give you a more elegant implementation.
I don’t have a code sample with Reassign task available at the moment. I have thought about putting a sample together, but I am swamped at work right now, so it will be some time before I get a sample out there. Ben and Mario have both gotten things working according to my concepts. Perhaps they can post their code until I can put a more formal sample together.
-Eugene
hi Eugene,
did u mean manually is create task to task list not use create task activty??
I meant using a CreateTask activity to create the new task, and then using the TaskProperties to transfer the task properties from the original task to the Reassigned task.
hi Eugene,
i’ve tried to create a new task using CreateTaskActivity, but problems are:
1. there will be an error, if i try to use CreateTaskActivity object that has been used to create previous task by loop.
2. there will be an error, if i create new object for CreateTaskActivity on runtime
I reuse my CreateTask activity within the loop. You just have to be careful how you create and initialize your correlation tokens. WF is very particular about correlation tokens. There is a lot of content on the subject:
http://www.google.com/search?q=createtask+activity+loop+correlation+token
hi Eugene,
thanx for help
it’s work
Hi,
I need Develop the workflow as like the same as out of box Approval workflow with Re-Assigning Task, Please guide me, how can i develop the Re-Assigning Task workflow using Visual Studio or Sharepoint Designer, What are the activity i have to use for that? and How to use?, Please provide me some sample code
Thanks.
Siva
Hi Siva,
Recreating the OOTB SharePoint approval workflow is not a trivial task. You would need to decode all of the data serialized the way I did with the TaskStatus. As I mentioned to Mario, the SharePoint Manager tool on Codeplex is a good place to start:
http://spm.codeplex.com/
http://weblogs.asp.net/gunnarpeipman/archive/2009/03/11/sharepoint-manager-2007.aspx
As I mentioned to Taufan, the OOTB workflows complete all workflow tasks and create a new task for any task action, including re-assignment. Your best bet in mimicking this behavior is to use a loop activity or a state machine workflow. Just make sure to watch how you handle your correlation tokens as SharePoint workflow is picky about tokens, particularly when the tokens are in a loop.
-Eugene
Hi Eugene,
This is a really helpful article – thanks for taking the time to write it.
I was wondering if this same approach and procedure is directly applicable in a SharePoint 2010 environment?
Could you confirm if you have tried this, and if not, can you suggest some ways I could consider doing this with SharPoint 2010 and Visual Studio 2010.
Regards.
Maz,
I have not tried this with SharePoint 2010 yet. In part, this is because SharePoint 2010 has such a richer workflow capability, that I don’t yet know if this is even needed with 2010. You can see some of the enhancements to SharePoint 2010 workflow here:
http://msdn.microsoft.com/en-us/library/ee537015.aspx
-Eugene
Eugene,
Thanks for your reply. I ask as I have been trying to get a custom workflow (developed in visual studio 2010) deployed and working in a SharePoint 2010 instance.
However, it always fails when the workflow is initiated: an exception message about no formURN being specified – I have looked around for a solution – the only (clearly) documented way I have found is the approach you outlined for MOSS 2007 (MSDN seems very content light in some areas). I really do not want to have develop new aspx pages or InfoPath forms, so if you do find something applicable for 2010 in the future, then please post it as it would solve a big headache!
Regards.
HI Eugene,
its me again hahahha
there is possible to associate custom workflow to custom Content Type???
thanx
Yes. Check out some these references:
http://technet.microsoft.com/en-us/library/cc514190(office.12).aspx
http://stackoverflow.com/questions/561835/how-do-you-bound-an-event-receiver-to-a-specific-custom-content-type
-Eugene
Hello Eugene,
thats a great post. I have it partially working in a few minutes. But I have a problem.
When the form is opened, in place of appearing Approve/Reject/Cancel buttons, the buttons that appear are Send Feedback/Cancel.
Do you know why it is this happening?
thank you lots.
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 Eugene,
First of all, thank you for your response.
It was my fault, I was assigning the task type id to a different task (not to the one I was testing).
Thank you for all again!!
Hey there — great example….once i got the correct settings in my CreateTask activities it worked beautifully!
Couple questions:
1. In the elements.xml youi have three URN entries and the all have the same settings — do these entries allow me to change the button labels at runtime? I.e. for Task0_FormURN I would like the buttons as you have them — Approve, Reject, Cancel. But for Task1_FormURN I would like to see only two buttons (for example) — Resubmit and Cancel (I would use this for a scenario where the reviewer requested additional info and the originator responds). Is this possible?. If so, where/how do I set the corresponding entries?
2. How/where can one see the actual form definition so that I can determine what the various fields are so I can preset them? Does that make sense? In my code I set:
Reviewtask_TaskProperties1.Title = “Pending CAPEX Request Review [Review Gate " + _curGateNum + "]“;
Reviewtask_TaskProperties1.AssignedTo = _curGateReviewer;
Reviewtask_TaskProperties1.Description = “The attached CAPEX Request requires your review and approval”;
Reviewtask_TaskProperties1.ExtendedProperties["comments"] = “”;
Reviewtask_TaskProperties1.ExtendedProperties["instructions"] = “Please review and approve/reject as appropriate”;
THis does properly preset Title and AssignedTo, but the “Description” field does not appear to map to anything and so that’s not being preset.
3. I’m using this form for a workflow that actually has an attached InfoPath form that is being routed — dio you know what/how/where I need to make a change so that the attachement is opened as a browser-enabled form and NOT in the InfoPath application? THe form is browser-enabled, and when I create it/edit it within the form library it exists in, it is opened as a browser-form. Only when I click on the attachment link associated with the task does it attempt to open InfoPath.
Thanks for any help you can provide.
rene
ONe more question if I may — I’ve been trying to figure out how to deal with the reassign and request change options, but it does not look like these provide a status value like Approve and Reject….As you indicated Approve and Reject return # and @, respectively. But when I step through my code and look at the ExtendedProperties values, I see # and @ for Approve/Reject, but the other options simply return a blank status.
I assume that the ExtendedStatusColumnValues ($Resources:ReviewFeedback_RejectedStatus) set in the element.xml define what those values are that are returned? If so, how/where do I specify what to return for Reassign and Req Change? Where do I set the appropriate .mapping for “$Resources:ReviewFeedback_RejectedStatus”?
Hi,
Did you get the answer for you r question?
Even i have a question in retrieving reassign task and change request values in the workflow.
Any help is appreciated.
Regards,
Calvin
Eugene,
I have created Declarative workflow in SharePoint Designer 2010 and then imported it to Visual Studio 2010. There were some missing pieces after the import like dll references, InfoPath form packaging, associating the workflow forms.
I have completed all the missing pieces.
I am able to associate the workflow to a content type. The workflow is getting started but the Approval Infopath Form has blank values in the fields like request by, comments etc..
I am using a custom approval content type which is assigned to the TasklistContenttypeId of the workflow element file.
Any idea why the Approval form is displaying blank values? Can you guide to resolve the issue?
Best Regards,
Amal