Understanding UpdateAllTasks activity in SharePoint Workflow

I recently got a case from a customer complaining that the UpdateAllTasks activity fails to change any of the properties of the currently active workflow tasks even though the activity executes without error.

The requirement is very simple.  In the Sequential workflow there are few CreateTask activities and one UpdateAllTasks activity.  The reason for having UpdateAllTasks activity is that, in case the workflow fails, all the tasks that have been created by the current workflow should get their properties (for e.g Title) modified in the UpdateAllTasks activity.  We do have the code to modify the task properties in UpdateAllTasks activity and it runs successfully.  Why aren’t we able to see the results in the UI then?  Has it got anything to do with the way UpdateAllTasks activity is implement in the workflow or are we missing something else in the workflow?

                                         WithoutOnTaskCreated

To understand this better, we first need to get our basics right.  SharePoint workflow always runs in batches.  I'll get back to the batching concept in a little while.  Before that let us try to understand different Interfaces provided by SharePoint Workflow.  There are 4 service interfaces used in SharePoint Workflow.

    • ISharePointService Interface
    • ITaskService Interface
    • IListItemService Interface
    • IWorkflowModificationService Interface

All of these services represent an ExternalDataExchangeService interface that enables workflow activities to request actions and handle events.  I’m not going to get into concept of local services communication.  You can find more details about CallExternalMethod and HandleExternalEvent activity.

Now, lets talk about batching service in SharePoint Workflow.  In a SharePoint workflow, say there are few activities like OnWorkflowActivated, CreateTask and a CodeActivity.  In the CodeActivity can we try to get task properties and modify them?  Yes, we can modify the properties but the question is, will the changes get reflected?  The answer is No!  But why?  The task created in CreateTask Activity is not really processed and hence not yet updated in the database.  So when will the activities get executed and update in database?  The rule is simple, when the workflow gets into either of these states.

  • When the workflow is persisted, all the activities till then gets executed. As the case has to be because the timeline for the workflow to wake up is not certain.  So all the activities until then will be executed and the changes will be reflected back in database.
  • When the workflow hits any of the events that implement the aforementioned interface. For e.g OnWorkflowItemChanged Event that uses ISharePointService interface.  Primary reason for this type of architecture is for improving the performance.

In the example taken, let us understand how it works.  The workflow executes when it hits OnWorkflowActivated Event (ISharePointService).  Then comes CreateTask and CodeActivity.  They don’t have any event that implements the services and hence the changes do not get reflected back in the database.  And so, any change that we make in the code activity will not be updated as the task created in CreateTask itself is not yet updated in database, it’s still in memory not in database.

Now let us come to our core problem.  UpdateAllTasks activity is no different from code activity. We can use the task properties of UpdateAllTasks to modify the properties of all tasks together.

 private void updateAllTasks1_MethodInvoking(object sender, EventArgs e)
 {
     updateAllTasks1_TaskProperties2.Title = "Title changed for all tasks";
 }

Even though we modify the task properties in UpdateAllTasks, the changes does not get reflected because the task created itself is in memory and is not updated in database.  We are trying to manipulate something which is in memory.  In order to fix this problem, use any of the Events that implement the SharePoint workflow service.  We can use OnTaskCreated Event (uses ITaskService) just after CreateTask, just to make sure that the task created actually gets updated in the database.  After that, we can modify the task properties within UpdateAllTasks and the changes will get reflected.

                                         WithOnTaskCreated