web
You’re offline. This is a read only version of the page.
close
Skip to main content
Community site session details

Community site session details

Session Id :
Microsoft Dynamics CRM (Archived)

Plugin Issue when set to Synchronous (Infinite loop)

(0) ShareShare
ReportReport
Posted on by

My plugin doesn't work when i set it to be synchrounous, it says that it entered a infinite loop on the error message, when i debug it i don't see any error, when i set to Async it works.

One thing i noticed, when it's set to Async, the plugin will run 1 one time on the create step and a few times (6~8) on the update step (the last one fails, informing about the infite loop), but i only created the case, i didn't updated and my workflows don't touch the fields that were supposed to trigger the update case step of the plugin. The plugin is filtered for only 2 fields (customerid and subjectid) that are not changed by my plugin, so i don't know why it keeps calling the plugin again and again.

This is my code:

public class CaseContractFill : IPlugin
    {
        Contract checkForContract(Guid accountId, IOrganizationService service)
        {
            //Bring all contracts associated with a account
            QueryExpression accountContractQuery = new QueryExpression
            {
                EntityName = Contract.EntityLogicalName,
                ColumnSet = new ColumnSet(true),
                Criteria = new FilterExpression
                {
                    Conditions = 
                    {
                        new ConditionExpression 
                        {
                            AttributeName = "accountid",
                            Operator = ConditionOperator.Equal,
                            Values = { accountId }
                        }
                    }
                }
            };

            DataCollection<Entity> accountContracts = service.RetrieveMultiple(accountContractQuery).Entities;

            //Check if account has a Active or Invoiced contract and return it
            if (accountContracts.Count > 0)
            {
                foreach (Contract item in accountContracts)
                {
                    if (item.StateCode == ContractState.Active || item.StateCode == ContractState.Invoiced)
                    {
                        return item;
                    }
                }
            }

            //Retrieves account information
            Account account = (Account)service.Retrieve(Account.EntityLogicalName, accountId, new ColumnSet(true));

            //Check if account has a parent and call this method again with that parent
            if (account.ParentAccountId != null)
            {
                return checkForContract(account.ParentAccountId.Id, service);
            }

            //If no Contract and/or no Parent returns null
            return null;
            
        }

        ContractDetail checkForContractLine(Guid contractId, Incident incident, IOrganizationService service)
        {
            //Query to bring all contract lines from a contract id
            QueryExpression accountContractQuery = new QueryExpression
            {
                EntityName = ContractDetail.EntityLogicalName,
                ColumnSet = new ColumnSet(true),
                Criteria = new FilterExpression
                {
                    Conditions = 
                    {
                        new ConditionExpression 
                        {
                            AttributeName = "contractid",
                            Operator = ConditionOperator.Equal,
                            Values = { contractId }
                        }
                    }
                }
            };
            DataCollection<Entity> contractLines = service.RetrieveMultiple(accountContractQuery).Entities;

            ContractDetail contractLine = null;

            // Check all contract lines to find one that matches the Case subject with the contract line product name, if none is found, returns a active one
            foreach (ContractDetail item in contractLines)
            {
                if ((item.StateCode == ContractDetailState.Existing) || (item.StateCode == ContractDetailState.Renewed))
                {
                    if ((incident.SubjectId != null) && (item.ProductId != null))
                    {
                        if (incident.SubjectId.Name.Equals(item.ProductId.Name))
                        {
                            contractLine = item;
                            break;
                        }
                        contractLine = item;
                    }
                }
            }

            return contractLine;
        }

        public void Execute(IServiceProvider serviceProvider)
        {
            ITracingService tracer = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = factory.CreateOrganizationService(context.UserId);

            try
            {
                Entity entity = (Entity)context.InputParameters["Target"];                
                Incident incident = (Incident)entity.ToEntity<Incident>();
                incident = (Incident)service.Retrieve(Incident.EntityLogicalName, incident.Id, new ColumnSet(true));

                Contract contract = checkForContract(incident.CustomerId.Id, service);
                
                if (contract != null)
                {
                    incident.ContractId = contract.ToEntityReference();

                    ContractDetail contractLine = checkForContractLine(contract.Id, incident, service);

                    if (contractLine != null)
                    {
                        incident.ContractDetailId = contractLine.ToEntityReference();
                    }

                    service.Update(incident);
                }
            }
            catch (Exception e)
            {
                throw new InvalidPluginExecutionException(e.Message);
            }
        }
    }


*This post is locked for comments

I have the same question (0)
  • Patrick O'Gorman Profile Picture
    166 on at
    RE: Plugin Issue when set to Synchronous (Infinite loop)

    man you rock!  thank you!  this not only fixed our bug but also sped the 'save' process up light years!!  super excited.

  • Community Member Profile Picture
    on at
    RE: Plugin Issue when set to Synchronous (Infinite loop)

    Hi Nuno,

    I changed my Execute method to the one you provided (just added the incidentId), now it doesn't go on the infinite loop anymore, when i set to synchonous it fills the contract but the contract line remains blank, if i manually refresh the page the line is set, do know why this happen and a way to resolve?

  • Verified answer
    Nuno Profile Picture
    2,005 on at
    RE: Plugin Issue when set to Synchronous (Infinite loop)

    Hi Claudio,

    Using ColumnSet(true) in queries is not a good practice, because this way you’re getting all attributes from CRM which may lead to performance issues. You should retrieve only the attributes you need.

    https://msdn.microsoft.com/en-us/library/gg309532.aspx

    Regarding to the Infinite loop issue it arises because you are updating all the attributes of the Incident, not only the two attributes you’re setting (ContractId and ContractLineId). You are updating all the attributes because you are updating an Incident object which contains all attributes due to ColumnSet(true).

    When you want to update an entity in CRM, it is also a good practice to create a new object and then set the attributes you want to update.

    Replace your code in Execute method by next:

     

    Entity entity = (Entity)context.InputParameters["Target"]; 
    Incident incident = (Incident)entity.ToEntity<Incident>();
    incident = (Incident)service.Retrieve(Incident.EntityLogicalName, incident.Id, new ColumnSet("customerid"));
    
    Contract contract = checkForContract(incident.CustomerId.Id, service);
    if (contract != null)
    {
      Incident incidentToUpdate = new Incident();
      incidentToUpdate.ContractId = contract.ToEntityReference();
      
      ContractDetail contractLine = checkForContractLine(contract.Id, incident, service);
    
      if (contractLine != null)
      {
         incidentToUpdate.ContractDetailId = contractLine.ToEntityReference();
      }
      service.Update(incidentToUpdate );
    }

    Regards,

  • Suggested answer
    Zohaib Uddin Khan Profile Picture
    2,811 on at
    RE: Plugin Issue when set to Synchronous (Infinite loop)

    Hi,

    IExecutionContext.Depth Property will come handy in this scenario.

    So, do the following change:

    public void Execute(IServiceProvider serviceProvider)
            {
                ITracingService tracer = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
                IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
                IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                IOrganizationService service = factory.CreateOrganizationService(context.UserId);
    
                if (context.Depth > 1) { return; }
    
                try
                {
                    Entity entity = (Entity)context.InputParameters["Target"];                
                    Incident incident = (Incident)entity.ToEntity<Incident>();
                    incident = (Incident)service.Retrieve(Incident.EntityLogicalName, incident.Id, new ColumnSet(true));
    
                    Contract contract = checkForContract(incident.CustomerId.Id, service);
                    
                    if (contract != null)
                    {
                        incident.ContractId = contract.ToEntityReference();
    
                        ContractDetail contractLine = checkForContractLine(contract.Id, incident, service);
    
                        if (contractLine != null)
                        {
                            incident.ContractDetailId = contractLine.ToEntityReference();
                        }
    
                        service.Update(incident);
                    }
                }
                catch (Exception e)
                {
                    throw new InvalidPluginExecutionException(e.Message);
                }
            }

    Don't forget to mark the post as Verified, if it worked. 

  • Suggested answer
    pavanmanideep Profile Picture
    1,331 on at
    RE: Plugin Issue when set to Synchronous (Infinite loop)

    Hi Claudio,

    I don't see any depth property used to prevent infinite loops in the plugin.

    include the statement in code to prevent infinite loops

    if (context.Depth > 1) { return; }

     

    Don't forget to mark the answer as verified if a forum member helped you out.

    Pavan Mani Deep

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Andrés Arias – Community Spotlight

We are honored to recognize Andrés Arias as our Community Spotlight honoree for…

Leaderboard > 🔒一 Microsoft Dynamics CRM (Archived)

#1
Aric Levin - MVP Profile Picture

Aric Levin - MVP 2 Moderator

#2
MA-04060624-0 Profile Picture

MA-04060624-0 1

Last 30 days Overall leaderboard

Featured topics

Product updates

Dynamics 365 release plans