简体   繁体   中英

CRM Plugin execution causing an infinite loop

I have a custom entity called item allocation and I'm triggering a plugin on post update of LastUpdatedOn field.

The plugin updates quantity available field on the same entity and no other fields.

I don't understand why it is causing an infinite loop. I'm getting the below error:

This workflow job was canceled because the workflow that started it included an infinite loop.

Any help would be appreciated. Here is my code.

Entity entItemAllocation = (Entity)context.InputParameters["Target"];

if (context.PostEntityImages.Contains("PostImage") && context.PostEntityImages["PostImage"] is Entity)
{
   //get PostImageEntity
   Entity postImageEntity = context.PostEntityImages["PostImage"];

   int qtyAvailable = 0;
   if (postImageEntity.Attributes.Contains("wo_lotnumber"))
      lotNum =  postImageEntity.Attributes["wo_lotnumber"].ToString();
   if (postImageEntity.Attributes.Contains("wo_itemnumber"))
      itemNum = ((EntityReference)postImageEntity.Attributes["wo_itemnumber"]).Id;

   if (postImageEntity.Attributes.Contains("wo_qtyavailable"))
      qtyAvailable = Convert.ToInt32(postImageEntity.Attributes["wo_qtyavailable"]);

   if (dictAssignLotQty.ContainsKey($"{lotNum}|{itemNum}"))
   {
      decimal assignLotQty = dictAssignLotQty[$"{lotNum}|{itemNum}"];
      qtyAvailable -= Convert.ToInt32(assignLotQty);

      entItemAllocation["wo_qtyavailable"] = qtyAvailable;
      service.Update(entItemAllocation);
   }
}

It looks like you have implemented this:

  1. On update of entItemAllocation .
  2. Update wo_qtyavailable on entItemAllocation .

CRM will recognise the the update occuring at step 2, and start your plugin again at step 1, this pattern will keep repeating. You now have an infinite loop. As a safeguard CRM will eventually stop the looping plugins.

In terms of ways to avoid this:

  1. Add some logical check into your code, eg don't update wo_qtyavailable if its already the correct value.

  2. Use a depth check.

Used by the platform for infinite loop prevention.

Every time a running plug-in or Workflow issues a message request to the Web services that triggers another plug-in or Workflow to execute, the Depth property of the execution context is increased. If the depth property increments to its maximum value within the configured time limit, the platform considers this behavior an infinite loop and further plug-in or Workflow execution is aborted.

//At the start of your plugin
//If depth is greater than 1 skip rest of plugin logic.
//In some scenarios you might need to use 2, 3, etc, you will have to work that out based on how many events are executing in CRM before your plugin is called.
if (context.Depth > 1) { return; }

//Rest of plugin logic
...
  1. Use attribute filtering on your plugin registration , this limits the number of fields that will trigger the plugin to execute.

  2. Run your plugin on pre-update , you can then set fields on the Target which will go into CRM without you having to make a seperate service.Update call.

As a side note;

Entity entItemAllocation = (Entity)context.InputParameters["Target"];
...
entItemAllocation["wo_qtyavailable"] = qtyAvailable;
...
service.Update(entItemAllocation);

This will send into CRM any field already contained in entItemAllocation , eg if the Target contains wo_name , that field will also be updated (to the same value). You probably want to avoid that, which can you do by creating a new entity object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM