Wednesday, September 11, 2019

Cautiously changing logic of existing workflow in Dynamic CRM


How to deal with Old workflow instances that are in waiting state with old Logic?

We can accept that we are blessed with the Wait Condition in Dynamic CRM. It could be used in many simple to complex tasks such as to send a friendly reminders/email after certain duration.

There could be many workflow sessions running in a waiting state considering a typical Live (Production) environment.

Re-Defining Workflow

Now imagine for some reason your business logic got changed and you need to redefine the logic in a workflow.

Newly added logic for a respective workflow will not be applicable for workflows instances which are already in a waiting or running state and your business may complaint that notifications to customer are still going on even though you have already roll-out new changes to the workflow.

Solution

To overcome such a problem, I did follow below steps.
Step 1) Get workflow sessions which are still going ON (WAITING STATE) with OLD LOGIC
Step 2) Cancel Old workflow session with OLD LOGIC
Step 3) Trigger New Workflow Session for those records whose process got cancelled.

.Net Code for above outline steps 

public class SwitchToNewWorkflowProcess
{
IOrganizationService _orgService;

const string regardingEntityType = "invoice";
Guid workflowId = new Guid("1E99FA9F-3708-4107-A110-38191CC2BE59");     //  (Email) License has Expired


public SwitchToNewWorkflowProcess(IOrganizationService _orgService)
{
    this._orgService = _orgService;
}

public void executionPlan()
{
    // Step 1) Get workflow sessions which are still going ON (WAITING STATE) with OLD LOGIC
    EntityCollection oldWorkflowsCollection = getOldWorkflows();

    foreach (Entity sessions in oldWorkflowsCollection.Entities)
    {
        if (sessions.Contains("regardingobjectid"))
        {
            Guid invoiceId = ((EntityReference)sessions["regardingobjectid"]).Id;
                           
            //Step 2) Cancel workflow with OLD LOGIC
            cancelOldWorkflow(sessions.Id);

            // Step 3) Trigger New Workflow Session for those records whose process got cancelled.
            instantiateNewWorkflow(invoiceId);                 
        }
        else
            Console.WriteLine("Process Session where Regarding is not Set : " + sessions.Id.ToString());
    }
    Console.WriteLine("End of Execution Plan");
}


// You need to change condition clauses in below fetch XML to get specific workflow sessions
private EntityCollection getOldWorkflows()
{
    string fetchXmlOldSystemJob =            

    EntityCollection oldWorkflowsCollection = _orgService.RetrieveMultiple(new FetchExpression(fetchXmlOldSystemJob));
    return oldWorkflowsCollection;
}

private void cancelOldWorkflow(Guid workflowInstanceId)
{
    Entity operation = new Entity("asyncoperation")
    {
        Id = workflowInstanceId    //
    };

    operation["statecode"] = new OptionSetValue(3);
    operation["statuscode"] = new OptionSetValue(32);

    _orgService.Update(operation);
}     

private void instantiateNewWorkflow(Guid entityId)
{
    var executeWorkflowRequest = new ExecuteWorkflowRequest()
    {
        WorkflowId = workflowId,      // Guid of workflow 
        EntityId = entityId           // Guid of record 
    };
    var executeWorkflowResponse = (ExecuteWorkflowResponse)_orgService.Execute(executeWorkflowRequest);
}
}

From you main method just invoke the executionPlan() method.

IOrganizationService _orgService;
_orgService = getOrgService();

SwitchToNewWorkflowProcess obj = new SwitchToNewWorkflowProcess(_orgService);
obj.executionPlan();






No comments: