locked
"This workflow job was canceled because the workflow that started it included an infinite loop..." RRS feed

  • Question

  • I have a Post Update-step for custom Plugin that are executing another Update on the same entity:

    I now get a Exception:

    I don' see why this would happen, because Update #2 doesn't change "log_bookedstartdate" or "log_bookedenddate" and a infinite loop should therefore be avoided.... or am I missing something here?

    regards,

    Marius H. Enerud

    Thursday, December 22, 2016 1:03 PM

All replies

  • Can you please provide full code of your plugin?

    Dynamics CRM MVP
    Read My blog
    Subscribe for one of my courses

    Thursday, December 22, 2016 2:32 PM
    Moderator
  • Hi,

    here are the full code for the plugin step:

     public PostUpdate(string unsecureConfig, string secureConfig) : base(unsecureConfig, secureConfig)
            {
                // Register for any specific events by instantiating a new instance of the 'PluginEvent' class and registering it
                base.RegisteredEvents.Add(new PluginEvent()
                {
                    Stage = eStage.PostOperation,
                    MessageName = "Update",
                    EntityName = log_workorders.GetLogicalName(),
                    PluginAction = ExecutePluginLogic
                });
            }
            public static void ExecutePluginLogic(IServiceProvider serviceProvider)
            {
                // Use a 'using' statement to dispose of the service context properly
                // To use a specific early bound entity replace the 'Entity' below with the appropriate class type
                using (var localContext = new LocalPluginContext<Entity>(serviceProvider))
                {
                    if (localContext == null)
                    {
                        throw new ArgumentNullException("localContext");
                    }

                    string preImageAlias = "preimage";
                    string postImageAlias = "postimage";

                    IPluginExecutionContext context = localContext.PluginExecutionContext;

                    Entity preImageWorkOrder = (context.PreEntityImages != null && context.PreEntityImages.Contains(preImageAlias)) ? context.PreEntityImages[preImageAlias] : null;
                    Entity postImageWorkOrder = (context.PostEntityImages != null && context.PostEntityImages.Contains(postImageAlias)) ? context.PostEntityImages[postImageAlias] : null;
                    Entity WorkOrder = (Entity)(context.InputParameters.ContainsKey("Target") ? context.InputParameters["Target"] : null);
                    Guid workorderid = WorkOrder.Id;

                    log_workorders workorder = WorkOrder.ToEntity<log_workorders>();
                    log_workorders preimageworkorder = preImageWorkOrder.ToEntity<log_workorders>();
                    log_workorders postimageworkorder = postImageWorkOrder.ToEntity<log_workorders>();

                    #region SMS (Booked appointment) functionality
                    // Booked start date and Booked end date have been deleted. SMS message must be deleted
                    if (preimageworkorder.log_Bookedstartdate.HasValue && !postimageworkorder.log_Bookedstartdate.HasValue
                        && preimageworkorder.log_Bookedenddate.HasValue && !postimageworkorder.log_Bookedenddate.HasValue)
                    {
                        using (OrganizationServiceContext ctx = new OrganizationServiceContext(localContext.OrganizationService))
                        {
                            var existingsms = (from s in ctx.CreateQuery<log_sms>()
                                               where s.log_SMS != null && s.log_SMS.Id == postimageworkorder.Id
                                               && s.log_DispatchStatus != null && !s.log_DispatchStatus.Value.Equals(182400003) // not dispatched
                                               select s);

                            foreach (var sms in existingsms)
                            {
                                localContext.OrganizationService.Delete(log_sms.GetLogicalName(), sms.Id);
                            }
                        }
                    }


                    // Booked start date or Booked end date have been updated. An SMS message must be created/updated
                    if (workorder.log_Bookedstartdate.HasValue || workorder.log_Bookedenddate.HasValue)
                    {


                        workorder.log_ScheduledBy = new EntityReference("systemuser", context.InitiatingUserId);
                     //   localContext.OrganizationService.Update(workorder);

                        using (OrganizationServiceContext ctx = new OrganizationServiceContext(localContext.OrganizationService))
                        {
                            string templatename = GetSMSTemplateName((int)postimageworkorder.log_TypeofWorkOrder.Value);

                            log_smstemplate smstemplate = (from st in ctx.CreateQuery<log_smstemplate>()
                                                           where st.log_name == templatename
                                                           select st).FirstOrDefault();
                            if (smstemplate != null)
                            {
                                EntityCollection customers = (EntityCollection)postimageworkorder["customers"];
                                Entity ap = customers.Entities[0];
                                EntityReference accountRef = (EntityReference)(customers.Entities[0])["partyid"];
                                Account account = localContext.OrganizationService.Retrieve(Account.GetLogicalName(), accountRef.Id, new ColumnSet(true)).ToEntity<Account>();

                                string smsbody = (string)smstemplate.log_SMSBody;

                                DateTime senddatetime = CalculateSendTime(postimageworkorder, smstemplate);

                                localContext.Trace("senddatetime: " + senddatetime.ToString());

                                log_sms existingsms = GetExistingSMS(localContext, preimageworkorder, postimageworkorder, ctx);

                                if (existingsms != null)
                                {
                                    UpdateExistingSMS(localContext, postimageworkorder, smsbody, senddatetime, existingsms);
                                }
                                else
                                {
                                    CreateNewSMS(localContext, postimageworkorder, accountRef, account, smsbody, senddatetime);
                                }
                            }
                        }
                    }

                    #endregion

                    #region No-show and SectorMobile (PDA) related functionality
                    // No-show logic
                    if (workorder.log_ProcessNoShow == "Activated") return;
                    else if (workorder.log_ProcessNoShow == "Activate")
                    {
                        BasicHttpBinding myBinding = new BasicHttpBinding();
                        myBinding.OpenTimeout = new TimeSpan(0, 3, 0);
                        myBinding.ReceiveTimeout = new TimeSpan(0, 3, 0);
                        myBinding.SendTimeout = new TimeSpan(0, 3, 0);
                        myBinding.CloseTimeout = new TimeSpan(0, 3, 0);
                        myBinding.Name = "BasicHttpBinding_ITwoWayAsyncVoid";
                        myBinding.Security.Mode = BasicHttpSecurityMode.None;
                        myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
                        myBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
                        myBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
                        EndpointAddress endPointAddress = new EndpointAddress(Utilities.GetConfigItem<string>("log_noshowactivationserviceendpoint", localContext.OrganizationService));


                        // get engineer id and country
                        EntityReference engineerRef = workorder.log_ReportedbyId ?? preimageworkorder.log_ReportedbyId;
                        if (engineerRef == null) localContext.Trace("engineerRef = null");
                        log_employee engineer = ((Entity)localContext.OrganizationService.Retrieve("log_employee", engineerRef.Id, new ColumnSet("log_employeenumber"))).ToEntity<log_employee>();
                        localContext.Trace("engineer: " + engineer.log_name);
                        string dataareaid = Utilities.GetConfigItem<string>("log_axdataareaid", localContext.OrganizationService);
                        string country = Utilities.GetConfigItem<string>("log_noshowactivationcountry", localContext.OrganizationService);

                        //the "old" noshow-solution (not working in TEST, therefore skip it)              
                        var servername = Environment.MachineName.ToLower();
                        if (!servername.Contains("dev") && !servername.Contains("test") && !servername.Contains("tst"))
                        {
                            NoShowActivationServiceClient noshowclient = new NoShowActivationServiceClient(myBinding, endPointAddress);
                            NoShow noshow = new NoShow();
                            noshow.ActivityNumber = workorder.log_ActivityNumber ?? preimageworkorder.log_ActivityNumber;
                            noshow.Country = country;
                            noshow.Engineer = engineer.log_EmployeeNumber;

                            noshowclient.ActivateNoShow(noshow);
                        }

                        string noshowendpoint = null;
                        using (var orgcontext = new OrganizationServiceContext(localContext.OrganizationService))
                        {
                            noshowendpoint = (from s in orgcontext.CreateQuery<log_sectormobileconfigurationsetting>()
                                              where s.log_name == "NoShowEndpoint"
                                              select s.log_Value).FirstOrDefault();
                        }

                        //the "new" noshow-solution
                        if (!string.IsNullOrWhiteSpace(noshowendpoint))
                        {
                            BasicHttpBinding mynoshowBinding = new BasicHttpBinding();
                            mynoshowBinding.OpenTimeout = new TimeSpan(0, 3, 0);
                            mynoshowBinding.ReceiveTimeout = new TimeSpan(0, 3, 0);
                            mynoshowBinding.SendTimeout = new TimeSpan(0, 3, 0);
                            mynoshowBinding.CloseTimeout = new TimeSpan(0, 3, 0);
                            mynoshowBinding.Name = "BasicHttpBinding_ITwoWayAsync";
                            mynoshowBinding.Security.Mode = BasicHttpSecurityMode.TransportWithMessageCredential;
                            mynoshowBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
                            mynoshowBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
                            mynoshowBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
                            EndpointAddress endPointAddressNoShow = new EndpointAddress(noshowendpoint);
                            NoShowBTService.WcfService_WorkOrderIntegration_v3Client client = new NoShowBTService.WcfService_WorkOrderIntegration_v3Client(mynoshowBinding, endPointAddressNoShow);
                            NoShowBTService.UpdateWorkorderEvent ev = new NoShowBTService.UpdateWorkorderEvent();
                            ev.ActivityNumber = workorder.log_ActivityNumber ?? preimageworkorder.log_ActivityNumber;
                            ev.EmployeeNumber = engineer.log_EmployeeNumber;
                            ev.EventType = NoShowBTService.UpdateWorkorderEventEventType.ActivateNoShow;
                            client.ClientCredentials.UserName.UserName = "xxx";
                            client.ClientCredentials.UserName.Password = "xxx";
                            client.UpdateWorkorderEvent(ev);
                        }

                        workorder.log_ProcessNoShow = "Activated";
                        localContext.Trace("Activated.");
                        if (localContext.PluginExecutionContext.InitiatingUserId == null) localContext.Trace("initiatinguserid = null");
                        localContext.Trace("InitiatingUserId: " + localContext.PluginExecutionContext.InitiatingUserId.ToString());
                        EntityReference callinguserRef = new EntityReference("systemuser", localContext.PluginExecutionContext.InitiatingUserId);
                        workorder.log_NoShowActivatedBy = callinguserRef;
                        localContext.OrganizationService.Update(workorder);
                        return;
                    }

                    // PDA logic
                    if (workorder.log_ProcessPDA == "Activated") return;
                    else if (workorder.log_ProcessPDA == "Activate")
                    {
                        BasicHttpBinding myBinding = new BasicHttpBinding();
                        myBinding.OpenTimeout = new TimeSpan(0, 3, 0);
                        myBinding.ReceiveTimeout = new TimeSpan(0, 3, 0);
                        myBinding.SendTimeout = new TimeSpan(0, 3, 0);
                        myBinding.CloseTimeout = new TimeSpan(0, 3, 0);
                        myBinding.Name = "BasicHttpBinding_ITwoWayAsyncVoid1";
                        myBinding.Security.Mode = BasicHttpSecurityMode.None;
                        myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
                        myBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
                        myBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
                        EndpointAddress endPointAddress = new EndpointAddress(Utilities.GetConfigItem<string>("log_wopdaupdateserviceendpoint", localContext.OrganizationService));
                        WorkOrderUpdateServiceClient WOupdateservice = new WorkOrderUpdateServiceClient(myBinding, endPointAddress);

                        EntityReference engineerRef = workorder.log_EmployeeId ?? preimageworkorder.log_EmployeeId;
                        if (engineerRef == null) throw new InvalidPluginExecutionException("Engineer must be specified before submitting to SectorMobile.");
                        log_employee engineer = ((Entity)localContext.OrganizationService.Retrieve("log_employee", engineerRef.Id, new ColumnSet(true))).ToEntity<log_employee>();
                        string engineerno = engineer.log_EmployeeNumber;
                        string country = Utilities.GetConfigItem<string>("log_noshowactivationcountry", localContext.OrganizationService);

                        //oppdaterer WO (gml metode)...
                        //BizTalk endpoint disabled in TEST, therefore skip it)            
                        var servername = Environment.MachineName.ToLower();
                        if (!servername.Contains("dev") && !servername.Contains("test") && !servername.Contains("tst"))
                        {
                            UpdateWorkOrder updateWO = new UpdateWorkOrder() { ActivityNumber = (workorder.log_ActivityNumber ?? preimageworkorder.log_ActivityNumber), Country = country, Engineer = engineerno };
                            WOupdateservice.UpdateWorkOrder(updateWO);
                        }

                        //oppdaterer WO (ny metode)...
                        string noshowendpoint = null;
                        using (var orgcontext = new OrganizationServiceContext(localContext.OrganizationService))
                        {
                            noshowendpoint = (from s in orgcontext.CreateQuery<log_sectormobileconfigurationsetting>()
                                              where s.log_name == "NoShowEndpoint"
                                              select s.log_Value).FirstOrDefault();
                        }

                        //oppdaterer WO products..
                        if (!string.IsNullOrWhiteSpace(noshowendpoint))
                        {
                            BasicHttpBinding mynoshowBinding = new BasicHttpBinding();
                            mynoshowBinding.OpenTimeout = new TimeSpan(0, 3, 0);
                            mynoshowBinding.ReceiveTimeout = new TimeSpan(0, 3, 0);
                            mynoshowBinding.SendTimeout = new TimeSpan(0, 3, 0);
                            mynoshowBinding.CloseTimeout = new TimeSpan(0, 3, 0);
                            mynoshowBinding.Name = "BasicHttpBinding_ITwoWayAsync";
                            mynoshowBinding.Security.Mode = BasicHttpSecurityMode.TransportWithMessageCredential;
                            mynoshowBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
                            mynoshowBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
                            mynoshowBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
                            EndpointAddress endPointAddressNoShow = new EndpointAddress(noshowendpoint);
                            NoShowBTService.WcfService_WorkOrderIntegration_v3Client client = new NoShowBTService.WcfService_WorkOrderIntegration_v3Client(mynoshowBinding, endPointAddressNoShow);
                            NoShowBTService.UpdateWorkorderEvent ev = new NoShowBTService.UpdateWorkorderEvent();
                            ev.ActivityNumber = workorder.log_ActivityNumber ?? preimageworkorder.log_ActivityNumber;
                            ev.EmployeeNumber = engineer.log_EmployeeNumber;
                            ev.EventType = NoShowBTService.UpdateWorkorderEventEventType.UpdateWorkorderProducts;
                            client.ClientCredentials.UserName.UserName = "xxx";
                            client.ClientCredentials.UserName.Password = "xxx";
                            client.UpdateWorkorderEvent(ev);
                        }

                        workorder.log_ProcessPDA = "Activated";
                        localContext.OrganizationService.Update(workorder);
                        return;
                    }
                    #endregion

                    #region Cancel WorkOrder/Contract/Installation if CancelOptyStatusCode is given
                    int opportunitystatuscode = -1;
                    if (preImageWorkOrder.Attributes.ContainsKey("log_canceloptystatuscode")) opportunitystatuscode = (int)preImageWorkOrder.Attributes["log_canceloptystatuscode"];
                    else if (WorkOrder.Attributes.ContainsKey("log_canceloptystatuscode")) opportunitystatuscode = (int)WorkOrder.Attributes["log_canceloptystatuscode"];

                    localContext.Trace("log_canceloptystatuscode = " + opportunitystatuscode);

                    if (opportunitystatuscode == -1) return;

                    EntityReference opportunityRef = (EntityReference)preImageWorkOrder.Attributes["log_regardingopportunity"];
                    Entity opportunity = localContext.OrganizationService.Retrieve("opportunity", opportunityRef.Id, new ColumnSet(true));

                    EntityReference installationRef = (EntityReference)preImageWorkOrder.Attributes["log_installationid"];
                    Entity installation = null;
                    if (installationRef != null)
                        installation = localContext.OrganizationService.Retrieve("log_installation", (Guid)installationRef.Id, new ColumnSet(true));

                    //Finding all contracts related to installation
                    var ceInstallation = new ConditionExpression("log_installationid", ConditionOperator.Equal, installation.Id);
                    //Finding all contracts with status active
                    var ceStatusReason = new ConditionExpression("statecode", ConditionOperator.Equal, 0);
                    var fe = new FilterExpression(LogicalOperator.And);
                    fe.Conditions.Add(ceInstallation);
                    fe.Conditions.Add(ceStatusReason);

                    var qe = new QueryExpression("log_contract") { Criteria = fe, ColumnSet = new ColumnSet(true) };

                    Entity contract = null;
                    DataCollection<Entity> contracts = localContext.OrganizationService.RetrieveMultiple(qe).Entities;
                    if (contracts != null && contracts.Count > 0)
                        contract = contracts[0];

                    SetStateRequest setOpportunityStateReq = new SetStateRequest();
                    setOpportunityStateReq.EntityMoniker = new EntityReference(opportunity.LogicalName, opportunity.Id);
                    setOpportunityStateReq.State = new OptionSetValue(0); // Open
                    setOpportunityStateReq.Status = new OptionSetValue(1); // In-Progress
                    SetStateResponse OpportunitySetStateResponse = (SetStateResponse)localContext.OrganizationService.Execute(setOpportunityStateReq);

                    if (installation != null)
                    {
                        SetStateRequest setInstallationStateReq = new SetStateRequest();
                        setInstallationStateReq.EntityMoniker = new EntityReference(installation.LogicalName, installation.Id);
                        setInstallationStateReq.State = new OptionSetValue(1); // Inactive
                        setInstallationStateReq.Status = new OptionSetValue(2); // Terminated
                        SetStateResponse InstallationSetStateResponse = (SetStateResponse)localContext.OrganizationService.Execute(setInstallationStateReq);
                    }

                    if (contract != null)
                    {
                        SetStateRequest setContractStateReq = new SetStateRequest();
                        setContractStateReq.EntityMoniker = new EntityReference(contract.LogicalName, contract.Id);
                        setContractStateReq.State = new OptionSetValue(1); // Inactive
                        setContractStateReq.Status = new OptionSetValue(2); // Terminated
                        SetStateResponse ContractStateResponse = (SetStateResponse)localContext.OrganizationService.Execute(setContractStateReq);
                    }

                    Entity closeOpportunity = new Entity("opportunityclose");
                    closeOpportunity.Attributes.Add(new KeyValuePair<string, object>("opportunityid", new EntityReference("opportunity", opportunity.Id)));
                    LoseOpportunityRequest loseOpportunityRequest = new LoseOpportunityRequest();
                    loseOpportunityRequest.OpportunityClose = closeOpportunity;
                    loseOpportunityRequest.RequestName = "LoseOpportunity";
                    loseOpportunityRequest.Status = new OptionSetValue(opportunitystatuscode);
                    LoseOpportunityResponse loseOpportunityResponse = (LoseOpportunityResponse)localContext.OrganizationService.Execute(loseOpportunityRequest);

                    SetStateRequest setWorkOrderStateReq = new SetStateRequest();
                    setWorkOrderStateReq.EntityMoniker = new EntityReference(WorkOrder.LogicalName, workorderid);
                    setWorkOrderStateReq.State = new OptionSetValue(2);
                    setWorkOrderStateReq.Status = new OptionSetValue(182400003);
                    SetStateResponse WorkOrderSetStateResponse = (SetStateResponse)localContext.OrganizationService.Execute(setWorkOrderStateReq);
                    #endregion
                }
            }


    • Edited by morris80 Friday, December 23, 2016 9:20 PM
    Friday, December 23, 2016 7:59 AM
  • Anyone have a clue? :-)
    Thursday, December 29, 2016 9:26 AM
  • Hi,

    Create a new object for the entity(log_workorders) and then add the necessary attributes. Do not directly push/assign the entity object from target/preimage/postimage.

    Technically when the entity object has some attributes on update, it is considered as update even though the attribute value is not modified. This causes infinite loop if I am not wrong. Below is a sample

    log_workorders workorders = new log_workorders() { Id = <Id of the record to be updated>}
    workorders.<attribute to be updated> = <value>;

    Please mark as resolved if this solves your problem. All the best.


    Ramanathan Rajendran MCTS - Dynamics CRM

    Friday, December 30, 2016 12:04 AM