Recently come across a business scenario where a workflow needs to be run after record being assign to others. The problem is workflow configured as wait after 1 hour, then update a field.
It is possible that during the 1 hour waiting time, user might reassign again~~again, result of that is multiple same workflow actually is running and waiting at the same time...what we want is just the running the latest workflow instance only.
To solve this problem, create a CRM 4 plugin to query related workflow with specific workflow name, check its status then update it to cancelled.
Register as pre-stage; synchronous, so that it won't cancelled the latest workflow instance .
string error = string.Empty;
ColumnSet colsWf = new ColumnSet(new string[] { "name", "statuscode", "asyncoperationid", "regardingobjectid" });
ConditionExpression conditionName = new ConditionExpression("name", ConditionOperator.Equal, workflowName);
ConditionExpression conditionRegardingObjectId = new ConditionExpression("regardingobjectid", ConditionOperator.Equal, recordId);
FilterExpression filter = new FilterExpression();
filter.FilterOperator = LogicalOperator.And;
filter.AddCondition(conditionName);
filter.AddCondition(conditionRegardingObjectId);
QueryExpression query = new QueryExpression(EntityName.asyncoperation.ToString());
query.Criteria = filter;
query.ColumnSet = colsWf;
BusinessEntityCollection results = service.RetrieveMultiple(query);
if (results.BusinessEntities.Count > 0)
{
for (int i = 0; i < results.BusinessEntities.Count; i++)
{
asyncoperation singleWorkflowInstance = (asyncoperation)results.BusinessEntities[i];
if (singleWorkflowInstance.statuscode.Value == AsyncOperationStatus.WaitingForResources || singleWorkflowInstance.statuscode.Value == AsyncOperationStatus.Waiting || singleWorkflowInstance.statuscode.Value == AsyncOperationStatus.InProgress || singleWorkflowInstance.statuscode.Value == AsyncOperationStatus.Pausing)
{
try
{
Status statusCanceled = new Status();
statusCanceled.Value = AsyncOperationStatus.Canceled;
AsyncOperationStateInfo state = new AsyncOperationStateInfo();
state.Value = AsyncOperationState.Completed;
SetStateWorkflowRequest request = new SetStateWorkflowRequest();
singleWorkflowInstance.statuscode = statusCanceled;
singleWorkflowInstance.statecode = state;
TargetUpdateAsyncOperation operation = new TargetUpdateAsyncOperation();
operation.AsyncOperation = singleWorkflowInstance;
UpdateRequest update = new UpdateRequest();
update.Target = operation;
UpdateResponse updated = (UpdateResponse)service.Execute(update);
}
catch (System.Web.Services.Protocols.SoapException ex)
{
error = "KillWorkflow Error " + ex.Message + "" + ex.StackTrace;
}
catch (Exception ex)
{
error = "KillWorkflow Error " + ex.Message + "" + ex.StackTrace;
}
}
}
if (!string.IsNullOrEmpty(error))
{
throw new Exception(error);
}
}