No, I don’t write a lot about coding on here often but since my mission statement for my blog is all things me and I just spent the last few hours digging through SDK to figure out how to cancel a workflow with the CRM 4.0 SDK I figured I should write a blog post. Google had nothing about it so hopefully the next person will find this. Be forewarned, I haven’t fully tested this so use it at your own risk. One thing I haven’t tested is how CRM behaves when you try to change status on something that is waiting for resources. I expect it will work but who knows.
The gist of it is instances of workflows are now contained in the asyncoperationbase table and entity. Go retrieve the asyncoperations you are interested in. In my case I would know the workflow name I was after as well as the CRM objectID of the record the workflow would be running on. Once I have that list I check and see if the status is an a status that I want to cancel. The statuses and states are listed in the SDK. You have to set both the status and state for the operation to take effect. It doesn’t throw an error like I recall CRM 3.0 doing about mismatched status and state combination’s, it just goes along its merry way and doesn’t change anything.
In CRM 3.0 you could use the SetStateWFProcessInstanceRequest but since everything around WFProcess was deprecated I am doing it with the TargetUpdateAsyncOperation as seen below.
TargetUpdateAsyncOperation operation = new TargetUpdateAsyncOperation();
operation.AsyncOperation = singleWorkflowInstance;
UpdateRequest update = new UpdateRequest();
update.Target = operation;
UpdateResponse updated = (UpdateResponse)service.Execute(update);
So here is the code I wrote to do it and it does indeed cancel a workflow. The Utils.GetCrm4Service() method is my own and you will need to either implement it yourself of just instantiate the crmService yourself in place. There are plenty of examples on how to do it. I’d love feedback if you use it or if you know of a better way.
public static void KillWorkflow(string workflowName, Guid entityId)
{
string error = “”;
CrmService service = Utils.GetCrm4Service(null, false);
ColumnSet colsWf = new ColumnSet();
colsWf.Attributes = new string[] { “name”, “statuscode”, “asyncoperationid”, “regardingobjectid”};
ConditionExpression conditionName = new ConditionExpression();
conditionName.AttributeName = “name”;
conditionName.Values = new string[] { workflowName };
ConditionExpression conditionRegardingObjectId = new ConditionExpression();
conditionRegardingObjectId.AttributeName = “regardingobjectid”;
conditionRegardingObjectId.Values = new string[] { entityId.ToString() };
FilterExpression filter = new FilterExpression();
filter.Conditions = new ConditionExpression[] { conditionName, conditionRegaridingObjectId };
filter.FilterOperator = LogicalOperator.And;
QueryExpression query = new QueryExpression();
query.ColumnSet = colsWf;
query.EntityName = EntityName.asyncoperation.ToString();
query.Criteria = filter;
BusinessEntityCollection results = service.RetrieveMultiple(query);
if (results.BusinessEntities.Length > 0)
{
for (int i = 0; i < results.BusinessEntities.Length; i++)
{
asyncoperation singleWorkflowInstance = (asyncoperation)results.BusinessEntities[i];
if(singleWorkflowInstance.statuscode.Value == AsyncOperationStatus.WaitingForResources ||
singleWorkflowInstance.statuscode.Value == AsyncOperationStatus.Waiting ||
singleWorkflowInstance.statuscode.Value == AsyncOperationStatus.Pausing ||
singleWorkflowInstance.statuscode.Value == AsyncOperationStatus.InProgress)
{
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 (error != null && !error.Equals(“”))
{
throw new Exception(error);
}
}
}