I know they are several samples available out there, but here is a merge the best parts I found.
This example will show how to notify a sharepoint workflow to move to next step.
Context
I'm creating a custom workflow. I need to notify the wf from outside the process (list event, console app,etc...).
The Workflow
The basic is to create a "fake" task and monitor the OnTaskChange event, then programmatically approve the task from outside the process.

The wf example is pretty simple: create a task, wait for changes then log a message in the workflow history.
Bind the CorrelationToken of the CreateTask1 to a new token on that will be exclusive for this task. Apply the same token to the OnTaskChanged1.
The while loop could be omitted in this example, I left it to suggest that you can add a validation at this point using the while condition.
No need to bind the OnTaskChanged Invoked event.
The CreateTask1_MethodInvoking provides the minimal infos to create the task, note that the AssignedTo property is left blank.
NOTE: In the feature that deployed the workflow I didn't specify an infopath form.
Therefore if you manually go to the workflow task list and click on the task you will get a message telling you that no xsn form is associated, nothing to worry about we'll do it through code :)
Notifying the workflow
In this example I chose to fire next step of the workflow from a console application.
And voila!
This example will show how to notify a sharepoint workflow to move to next step.
Context
I'm creating a custom workflow. I need to notify the wf from outside the process (list event, console app,etc...).
The Workflow
The basic is to create a "fake" task and monitor the OnTaskChange event, then programmatically approve the task from outside the process.
The wf example is pretty simple: create a task, wait for changes then log a message in the workflow history.
Bind the CorrelationToken of the CreateTask1 to a new token on that will be exclusive for this task. Apply the same token to the OnTaskChanged1.
The while loop could be omitted in this example, I left it to suggest that you can add a validation at this point using the while condition.
private void createTask1_MethodInvoking(object sender, EventArgs e)
{
var ct = sender as CreateTask;
ct.TaskId = Guid.NewGuid();
var spTaskProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
spTaskProperties.Title = String.Format("{0} Step1", this.workflowProperties.Item.Name);
ct.TaskProperties = spTaskProperties;
}
No need to bind the OnTaskChanged Invoked event.
The CreateTask1_MethodInvoking provides the minimal infos to create the task, note that the AssignedTo property is left blank.
NOTE: In the feature that deployed the workflow I didn't specify an infopath form.
Therefore if you manually go to the workflow task list and click on the task you will get a message telling you that no xsn form is associated, nothing to worry about we'll do it through code :)
Notifying the workflow
In this example I chose to fire next step of the workflow from a console application.
static void Main(string[] args)
{
using (var site = new SPSite("http://[site_url]"))
{
using (var web = site.OpenWeb())
{
// retreive the list where the workflow is running
var list = web.Lists["myList"];
// find the item with the task to complete (for the example my item's ID is 1)
var item = list.Items.Cast<SPListItem>().First(c => c.ID == 1);
// find the latest active workflow
var wfs = site.WorkflowManager.GetItemActiveWorkflows(item).Cast<SPWorkflow>();
var wfID = wfs.OrderByDescending(c => c.Created).First();
// fetch workflow tasks
var wfTasks = item.Tasks;
// find the correct task
var task = (SPListItem)wfTasks.Cast<SPWorkflowTask>().First(
c => c.WorkflowId.Equals(wfID.InstanceId)
&& c.Title.Contains("Step1"));
// build a hashtable with the values to be changed to mark the task as complete
var ht = new Hashtable();
ht[SPBuiltInFieldId.Completed] = true;
ht[SPBuiltInFieldId.PercentComplete] = 1;
string taskStatus = SPResource.GetString(new CultureInfo((int)task.Web.Language, false), "WorkflowTaskStatusComplete", new object[0]);
ht[SPBuiltInFieldId.TaskStatus] = taskStatus;
// alter the task using a trick to prevent task lock issue
AlterTask(task, ht, true, 5, 100);
}
}
}
public static bool AlterTask(SPListItem task, Hashtable htData, bool fSynchronous, int attempts, int millisecondsTimeout)
{
// check this link for more details: http://geek.hubkey.com/2007/09/locked-workflow.html
if ((int)task[SPBuiltInFieldId.WorkflowVersion] != 1)
{
SPList parentList = task.ParentList.ParentWeb.Lists[new Guid(task[SPBuiltInFieldId.WorkflowListId].ToString())];
SPListItem parentItem = parentList.Items.GetItemById((int)task[SPBuiltInFieldId.WorkflowItemId]);
for (int i = 0; i < attempts; i++)
{
SPWorkflow workflow = parentItem.Workflows[new Guid(task[SPBuiltInFieldId.WorkflowInstanceID].ToString())];
if (!workflow.IsLocked)
{
task[SPBuiltInFieldId.WorkflowVersion] = 1;
task.SystemUpdate();
break;
}
if (i != attempts - 1)
Thread.Sleep(millisecondsTimeout);
}
}
return SPWorkflowTask.AlterTask(task, htData, fSynchronous);
}
And voila!
Comments