Brian Farnhill Australian SharePoint Developer and Lecturer

How to cancel a workflow programmatically

Tags: SharePoint, Workflow

came across this one today, I needed to look at a list item to see if a workflow was running on it and then cancel the workflow from that same bit of code. Now removing the workflow all together is quite simple, you can use SPWorkflowManager.RemoveWorkflowFromListItem() method, which will remove all trace of the workflow ever existing. That wasn't really what I was after, I wanted it to look as if it had been canceled from the UI with the "Terminate this workflow" link on the workflow status page. This requires a bit more code.

Essentially you use the static SPWorkflowManager.CancelWorkflow() method to do this, but there are a couple of catches:

  1. You have to cancel all the tasks for the workflow first
  2. The user canceling the workflow must have permission to do this through the UI, otherwise you will get an exception

So to put all of that into code, it would look something like this:

SPSecurity.RunWithElevatedPrivileges(delegate()
{
    using (SPSite site = new SPSite(properties.SiteId))
    {
        using (SPWeb web = site.OpenWeb(properties.RelativeWebUrl))
        {
            SPWorkflowManager manager = site.WorkflowManager;
            SPListItem item = web.Lists[properties.ListTitle].GetItemById(properties.ListItemId);
            foreach (SPWorkflow workflow in manager.GetItemActiveWorkflows(item))
            {
                foreach (SPWorkflowTask t in workflow.Tasks)
                {
                    t["Status"] = "Canceled";
                    t.Update();
                }
                SPWorkflowManager.CancelWorkflow(workflow);
            }
        }
    }
});

The above code was written to run within the context of an event handler, which is where the 'properties' variable comes from. The highlights of the above example are the SPSecurity.RunWithElevatedPrivileges part, which will allow any user to terminate the workflow, and then the foreach loop that runs over the workflow tasks to cancel them. It is also worth noting that my tasks in this case were of a custom content type (still inheriting from 'Workflow Task') but you still refer to them with the SPWorkflowTask class.

So after that has run the workflow will show up as canceled in the UI, citing the System Account as the user who canceled it. If you want to have a specific user cancel it you would need to swap the RunWithElevatedPrivileges bit for something that would impersonate a specific user who had permission to terminate the workflow.

Comments powered by Disqus