Hi All,
I want to retrieve records from child entity (my_child) from opportunity but it runs into infinite loop.
I have registered this plugin on Update of Opportunity field (my_field).
Message:Update
Primary Entity: Opportunity
Filtering Attributes: new_field
Stage:Post-Operation (Synchronous)
My Code
ITracingService tracingService =
(ITracingService)serviceProvider.GetService(typeof(ITracingService));
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
Entity entity = (Entity)context.InputParameters["Target"];
if (entity.LogicalName != "opportunity")
return;
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
Guid parentId = entity.Id;
var query = new QueryExpression("new_child"); //child entity
query.Criteria.AddCondition(new ConditionExpression("new_opportunity", ConditionOperator.Equal, parentId)); //new_opportunity is the lookup name in child entity
query.ColumnSet = new ColumnSet(true);
var results = service.RetrieveMultiple(query);
if (results.Entities.Any())
{
entity["new_testfee"] = "True";
}
else
{
entity["new_testfee"] = "False";
}
service.Update(entity);
Business Process Error
System.ServiceModel.FaultException`1[Microsoft.Xrm.Sdk.OrganizationServiceFault]: This workflow job was canceled because the workflow that started it included an infinite loop. Correct the workflow logic and try again. For information about workflow logic, see Help. (Fault Detail is equal to Exception details:
ErrorCode: 0x80044182
Message: This workflow job was canceled because the workflow that started it included an infinite loop. Correct the workflow logic and try again. For information about workflow logic, see Help.
TimeStamp: 2018-10-01T15:54:13.4504671Z
What am I doing wrong?
Thank you guys.
Finally, I got rid of the infinite loop issue by adding context.depth>1 check.
Also it worked by registering the plugin on pre-operation sync.
Update your code as below:
ITracingService tracingService =
(ITracingService)serviceProvider.GetService(typeof(ITracingService));
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
Entity entity = (Entity)context.InputParameters["Target"];
if (entity.LogicalName != "opportunity" || context.Depth > 1)
{
return;
}
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
Guid parentId = entity.Id;
var query = new QueryExpression("new_child"); //child entity
query.Criteria.AddCondition(new ConditionExpression("new_opportunity", ConditionOperator.Equal, parentId)); //new_opportunity is the lookup name in child entity
query.ColumnSet = new ColumnSet(true);
var results = service.RetrieveMultiple(query);
if (results.Entities.Any())
{
entity["new_testfee"] = "True";
}
else
{
entity["new_testfee"] = "False";
}
service.Update(entity);
I'm also surprised no-one suggested to use the pre-operation phase and to manipulate the update request before it was sent to the database - I'm obviously sneaker than others around here (or I've hit this issue too many times before)..
Message:Update
Primary Entity: Opportunity
Filtering Attributes: new_field
Stage:Pre-Operation (Synchronous)
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService)); IPluginExecutionContext context = (IPluginExecutionContext) serviceProvider.GetService(typeof(IPluginExecutionContext)); if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity) { Entity entity = (Entity)context.InputParameters["Target"]; if (entity.LogicalName != "opportunity") return; IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId); Guid parentId = entity.Id; var query = new QueryExpression("new_child"); //child entity query.Criteria.AddCondition(new ConditionExpression("new_opportunity", ConditionOperator.Equal, parentId)); //new_opportunity is the lookup name in child entity query.ColumnSet = new ColumnSet(true); var results = service.RetrieveMultiple(query); if (results.Entities.Any()) { entity["new_testfee"] = "True"; } else { entity["new_testfee"] = "False"; } // you don't actually need this line but keep it so you can see what is happening were you to return to the code later context.InputParameters["Target"]=entity;
Hi MN,
This is expected behaviour if you update the same field in the plugin which triggers an update. Idealy you shouldn't have a design where you need to update the same field which triggers an update but if you do have some business requirement, you can put the Depth chck.
Read more about this here: community.dynamics.com/.../crm-plugins-stopping-infinite-loops-and-understanding-pluginexecutioncontext-depth
Hope this helps.
Hi,
If you register plugin in update message and inside the plugin you are updating same primary entity in which entity event you fired so it's expected that in under same context plugin will fall infinite loop. In this scenario to restrict this you need to check depth of the context property.
Try with this - added the depth check in your code.
ITracingService tracingService =
(ITracingService)serviceProvider.GetService(typeof(ITracingService));
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
Entity entity = (Entity)context.InputParameters["Target"];
if (entity.LogicalName != "opportunity")
return;
if (context.Depth > 1)
return;
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
Guid parentId = entity.Id;
var query = new QueryExpression("new_child"); //child entity
query.Criteria.AddCondition(new ConditionExpression("new_opportunity", ConditionOperator.Equal, parentId)); //new_opportunity is the lookup name in child entity
query.ColumnSet = new ColumnSet(true);
var results = service.RetrieveMultiple(query);
if (results.Entities.Any())
{
entity["new_testfee"] = "True";
}
else
{
entity["new_testfee"] = "False";
}
service.Update(entity);
Hi M N,
Try adding this to your code.
if (context.Depth > 1) { return; }