A very long time ago now, I had the ambition to write an end-to-end blog post series called “A Humble Tribute to the Leave Form”. The intent was to show InfoPath Forms Services 2007 in all its glory – from its initially seductive, demo friendly first impressions, through to all of the dodgy workarounds and .net code required to get it to adequately handle a relatively simple business process like employee leave applications.
As it happened, I got through seven and a half blog posts and never finished it as events kind of overtook me. Its a pity because I didn’t get to the nasty bits. But one of the side effects of getting as far as I did, was that I ended up getting a lot of work developing leave forms!
Thus, now that SharePoint 2010 is upon us, it was inevitable that I would eventually get called to develop a leave form for this new edition. I now have done so, and in the process learnt a couple of new things that I thought were blogworthy – especially around getting things to play nice in a sustainable manner.
I came to realise that anytime you write any content that involves InfoPath, you end up with a stupid number of screenshots, and you are perpetually torn on the amount of detail to cover. So this time, rather than do a twelve post monster, I’ll just do 2 posts (real programmers will still find this post waffly but hopefully normal humans won’t).
I am not going to do a total beginners course here, I will assume instead you have done some basic InfoPath and SharePoint Designer workflows previously, and now want to know some interesting ways to do a general approval type process using SharePoint 2010. My main focus here is to deal with handling browser based InfoPath forms with SharePoint Designer workflows.
Setting the scene
To set the scene, I thought that instead of a leave form example, lets use an employee termination example instead. I have published such a form to SharePoint as a site content type called Form-EmployeeTermination. Below is the form with four perfectly legitimate reasons why someone should face instant dismissal.
Okay I realise there is a bit of testosterone there – but as far as I am concerned, even one of those reasons are grounds for instant dismissal!
To complete the scenario, I thought to myself, who in all the world right now would I most like to sack. The answer came quickly…
So here is the scenario. I am going to show how to leverage SharePoint 2010 new features to sack Justin Bieber. As part of sacking Justin Bieber, we will optimise the workflow to work with forms services and play nice with browser based rendering.
How it was…
Now in SharePoint 2007, you would likely publish the above form as a content type, associate that content type to a forms library and create a SharePoint designer workflow for that library. Then it would be exceedingly likely that you would utilise one of the three out of the box task based workflow actions, namely;
- Collect Data from a User
- Assign a Form to a Group
- Assign a To-do Item
The reason you would utilise one of these is because they create a task for someone to take an action. So for example, a user requests that Justin Bieber be terminated, a task is assigned to Justin’s boss to terminate him. When said boss has marched Justin Bieber out of the office, he then marks the task as complete in SharePoint.
Each of the above three actions served a particular purpose.
- Assign a To-do Item simply created a very basic task with an “Approve/Reject” button.
- Collect Data from a User allowed you to customise the task form and collect additional data beyond the Approve/Reject
- Assign a Form to a Group did the same as Collect Data from a User, except it could assign the task to multiple users.
I tended to use Collect Data from a User most of the time. because it passed you the ID of the newly created task in the task list. This was important if the task contained more than just an Approve or Reject button. Continuing our employee termination example, we might have a checkbox to note whether Justin Bieber cried or not when he was sacked.
Therefore, if the workflow needed to take an action based on whether Bieber was a blubbering cry-baby or not, then Collect Data from a User was the only workflow action that was suitable as we would need to refer to the task later, to check the Cry-Baby column.
These workflow actions also did a few other things behind the scenes. The approve task created was actually a site content type, with its own customised edit task form. SPD 2007 would create auto-generated ASPX pages for the task, incorporating any custom fields created. (If you want more detail about that then visit the “Theory Interlude” section of this post.)
How it is now…
One of the major improvements of SPD workflows with SharePoint 2010 is the integration of InfoPath. In SP2010, the aforementioned three workflow actions still exist, but when you use them, the customised task form is created as an InfoPath form embedded into the built in WrkTaskIP.aspx page, instead of an auto-generated ASPX page.
The screenshot below shows the basic idea. I created a simple list workflow using the Assign a To-do Item and published it. If we examine the workflow properties after publishing, we see that the workflow initialisation form and custom task are listed. I have highlighted the form for the task below.
Note that there is now a form with a name that matches the name of the To-Do action. If we click on this form, we can now edit it in InfoPath and republish it. Below is a before and after dodgy InfoPath pimping effort of the Terminate Employee task form.
If I run this workflow on an item, check out the task created. It simply renders the published InfoPath form that I modified.
So all in all, this is a great improvement over SharePoint 2007 SPD workflows. Being able to utilise InfoPath to control the look and feel of workflow forms is very handy indeed.
Having showed you this now, I want you to forget it! For reasons that I will explain later, these three workflow actions should be considered legacy in many circumstances.
Dealing with Forms Services
Our next stop on our journey to sack Justin Bieber is to deal with a common problem that occurs when SharePoint Designer Workflows are associated with published InfoPath Forms. If we take another close look at our dodgy pimped task form, you will see that there is a reference to the original form that triggered the workflow. It is a hyperlink next to the “This workflow task applies to” text.
The problem is when we click the link, instead of the form loaded in the browser, we are prompted to save or open an XML file as shown below.
This is very common issue that is frustrating for new players. The related list item link always references the original list/library and item that the workflow was triggered from. It has no idea that this is a URL to be rendered via forms services. The default URL for the above example when referred to as an item in a form library is
Yet when rendered within forms server, the URL is:
So, the problem is that the wrong URL is being passed into the task item as the related list item. The forms services URL is never used and therefore the form is not displayed in the browser. Ages ago, I documented a particularly crap workaround, before someone pointed out to me that if you simply add ?OpenIn=browser to the original URL, it will auto-magically redirect to the forms services URL. i.e.
http://sp/forms/Justin Bieber.xml?OpenIn=Browser will render an InfoPath form via forms services.
So our mission here is to change the reference to the original Justin Bieber termination request. By appending the OpenIn=Browser parameter to the URL, we ensure that the form is rendered by forms services.
If we take a closer look at the task as it is rendered in the browser, you can see that the InfoPath form is actually embedded inside another page. You might also notice that the hyperlink to the Justin Bieber termination form that triggered the workflow, is not part of the embedded InfoPath form. It is part of the surrounding page.
The page that displays the workflow task is called WrkTaskIP.aspx (presumably Workflow Task for InfoPath?) and is a system file that resides in the 14 Hive (C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS – this file also exists in SharePoint 2007 but is only used with Visual Studio workflows).
Now we all know these days that anything that lives in the Layouts folder should be treated with caution, and directly modifying this file is a giant no-no. Fortunately, as I will show in a bit, we can make a copy of this page and tell our task content type to use that copy.
But since we are here at the default page, lets have a peek inside this file to the relevant section and see what is going on.
3: <td width="10" valign="center" style="padding: 4px;">
4: <img IMG SRC="/_layouts/images/Workflows.gif" alt=<%SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(GetLocString("WrkTask_PageTitle")),Response.Output);%>/>
7: <% SPHttpUtility.NoEncode(m_pageDescription,Response.Output); %>
11: <InfoPath:XmlFormView id="XmlFormControl" runat="server" style="width:100%;"/>
But not all of us are developers and I have another idea. Let’s make the copy of WrkTaskIP.aspx, but remove the hyperlink reference to the form altogether. Instead, lets use the embedded InfoPath form to do the job of rendering the hyperlink to the form. At least that way, we have more control over the hyperlink that is generated.
To do this, we have three major steps to complete.
- Changing the workflow action to “Start Approval Process” to take advantage of the richer SharePoint data it provides
- Making a copy of WrkTaskIP.aspx and updating the task content types
- Modifying the task form to display the correct hyperlink
Step 1: The one workflow action to rule them all
First up, we are going to use a new workflow action that is SP2010 only. The reason for doing this will become clear later. For simplicity I will create a list based workflow called “Employee Termination”, as opposed to a reusable one.
Create a new workflow and assign it to the list where your form content type has been published to (In my example it is simply a form library called “forms”).
In the newly created workflow, choose “Start Approval Process” from the actions button in the ribbon.
Now up until this point, you would think this looks and feels like a regular workflow action. But as you will see, this innocuous looking action packs a hell of a lot of punch! First up, lets for now, assign this approval process to one user – the administrator account. We do this by clicking on the last parameter – the hyperlinked “these users” link.
While we are here, let’s take a quick look at this screen. This workflow action allows you to add more than one participant, as well as set some defaults, such as the title of the workflow task, as well as being able to set a task duration as shown below.
At this point we have configured the workflow participants. The next step is to delve into an innocent looking hyperlink that opens up a world of possibilities.
Click on the “Approval” hyperlink and you will be presented with a page that controls this new workflow action. This innocuous looking page has within it some impressive functionality. We will examine a little of it as we work through this scenario.
Let’s give this task a better name than “Approval”. We will call it “Employee Termination Request”.
Next step, we will add an additional field to the workflow approval task. I previously referred to the need to know if a terminated employee cried like a baby when they were sacked, so let’s add a Boolean field to represent this.
From the “Task Form Fields” section above, you will see a “new” button. From there you add a new field and set its type.
Note that once the field has been added, you can also control if it required or not in the resulting form.
Next, let’s make the form more user friendly by re-labelling some of the task outcomes. Again we will not get into the depth of this here – you can think of it as customising the buttons on the soon to be created task form. Let’s change Approve to “Terminate!”, Rejected to “No Way!”, and add a third task outcome called Warning with the button text of “Reprimand!”
Now that we have set these initial parameters, lets save the workflow and examine the InfoPath form that has been generated.
Using the breadcrumb in SharePoint Designer, choose the “Editor” link and then choose “Workflow Settings” from the ribbon
At this point. there are no generated InfoPath forms (note that the Forms section is empty in the bottom right).
Let’s publish this workflow and take a look at what happens in the aforementioned Forms section.
Aha! Now we have two forms. One is the workflow initiation form and the other is the task form. Taking a peek at the generated task form in InfoPath, we can see that it reflects the settings we applied earlier (check the buttons).
Additionally, a workflow task content type has been created with the same name. That task has been configured to use the above form.
This content type is important as we need to make a modification to it in part two.
Since the workflow has been published, let’s test where we have got to. I have my original Justin Bieber sacking form in the form library, so let’s manually trigger the workflow and take a look at the task created.
If you look at this form, you can see that my adjusted buttons have been created, and the additional crybaby Boolean field has been created.
At this point, this post is getting kind of huge, so let’s leave it at step 1. In part 2 of this series, we will make a copy of WrkTaskIP.aspx, modify the task content type to use the copy and then tweak the above form to display the reference to Justin Bieber via forms services. I’ll also show you another neat trick (and some InfoPath suckiness too).
Thanks for reading