Workflow Tasks with Predecessors

During the last weeks I had to work around a workflow project with some specific requirements. In particular, one of the requirements was to support workflow tasks with predecessors. As you probably know, tasks in SharePoint are based on the well-known Task content type (ID: 0x0108), and “Workflow Task (SharePoint 2013)” content type inherits from it (ID: 0x0108003365C4474CAE8C42BCE396314E88E51F). Thus, because the Task content type has a Predecessors field of type LookupMulti in its set of fields, it should be easy to satisfy the customer’s requirement.

However, you know … we’re in the SharePoint world and … what’s looks easy is not always that easy Sorriso …

SharePoint Designer 2013 Native Actions

In fact, if you take a look at the “Assign Task” action in SharePoint Designer 2013 – as you can see from the following figures – it is missing the option to configure predecessor.
spd2013-task-form-01_thumb_21594D38
spd2013-task-form-02_thumb_21594D38
And it is the same for the “Start a task process” action.

Visual Studio 2013 Native Activities

Thus, I moved to Visual Studio 2013 … just to check how the corresponding activities (SingleTask and CompositeTask) behave in the low level workflow designer. However, even in Visual Studio 2013 there is the same lack of capability (see next figures), of course!
vs2013-task-form-01_thumb_21594D38
vs2013-task-form-02_thumb_21594D38
One more time, the same happens with the CompositeTask activity, as well.

Never Give Up!

Trying to figure out a possible solution, I created a bunch of tasks with relationships in a classic tasks list. Then, using the powerful REST API of SharePoint 2013 I queried for a task item, which I manually created with some predecessors. In the following figure you can see the OData/XML content of such a task.
ie-task-content-01_thumb_21594D38
Let’s concentrate on the PredecessorsId element:
ie-task-content-02_thumb_21594D38
In JSON (Accept: application/json;odata=nometadata) the same content looks like the following one:
json-task-01_thumb_21594D38
Again, the PredecessorsId property, under the cover in JSON source text, will look like this:

{ “PredecessorsId”: [14,15] }

The Developer Solution

Thus, here is the solution to my requirement! I can simply leverage a bunch of REST API calls to update a task created either in SharePoint Designer 2013 or in Visual Studio 2013, in order to set the content of the PredecessorsId field.

I used Visual Studio 2013, just because in my case that was the tool used to create the whole SharePoint App solution. However, you can do almost the same within SharePoint Designer 2013, as well.

To accomplish my goal, I created a custom workflow activity in order to reuse this capability whenever I will need it. Here you can see the outline of the custom activity.
custom-activity-01_thumb_21594D38
The custom activity accepts a couple of input arguments:
custom-activity-arguments-01_thumb_21594D38
Those are the target WorkflowTaskId (IN: Int32), and the list of predecessors provided as an input argument of type ICollection, in order to support multiple predecessors.

First of all, I retrieve the URL of the target web site, which in my case is the app web site. Then, I retrieve the FormDigest value, using another custom activity of mines, in order to being able to safely submit the task item update request via REST.

The custom activity to retrieve the FormDigest is really trivial. Here it is:
custom-activity-02_thumb_21594D38
I simply query the _api/ContextInfo URL using a POST method, and providing an HTTP Header of type Accept with a value of “application/json;odata=nometadata”. Then, I retrieve the FormDigestValue property from the JSON object returned by the HTTP REST call.

Just after retrieving the FormDigest value I can create a JSON request for updating the target task item. Using a ForEach activity over the ICollection input argument, I collect all the IDs of the predecessors into a String variable, which at the end will assume a value like this:

{ “PredecessorsId”: [14,15] }

This JSON content will be the content of the REST API request to update the target task item.

Then, I build a DynamicValue variable, which will hold the HTTP Request Headers, which are required to submit the update request. Here you can see the configured headers:
rest-request-headers-to-update_thumb_21594D38
As you can see, I configure the following headers:

  • [Accept: application/json;odata=nometadata] in order to instruct SharePoint to answer using JSON light, without metadata
  • [X-RequestDigest: formDigest] to provide the FormDigest value
  • [X-HTTP-Method: MERGE] to instruct SharePoint to merge our properties (the PredecessorsId field in our case) with the other fields of the target item
  • [IF-MATCH: *] to ignore concurrency update conflicts, if any
  • [content-type: application/json;odata=nometadata] to inform SharePoint that the request content will be in JSON light format
  • [content-length: lenghtOfTheJSONRequest] to properly complete the HTTP request

Lastly, I simply call an HttpSend activity providing all these information and configuring a POST method with the URL of the target task item, which will be something like this:

https://tenant-appID.sharepoint.com/sites/HostSite/AppName/_api/web/lists/getByTitle(‘WorkflowTaskList’)/Items(16)

And you’re done … the task will be configured to support predecessors!

I hope you will find this post useful. Please, feel free to contact me via Twitter (@PaoloPia) or email (paolo at pialorsi.com) in case of any further need.