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