问题
Another MS CRM question from me, I'm afraid. I've got the following code being executed on the update of a contact record but it gives me an error saying the job was cancelled because it includes an infinite loop. Can anyone tell me why this is happening, please?
// <copyright file="PostContactUpdate.cs" company="">
// Copyright (c) 2013 All Rights Reserved
// </copyright>
// <author></author>
// <date>8/7/2013 2:04:26 PM</date>
// <summary>Implements the PostContactUpdate Plugin.</summary>
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.1
// </auto-generated>
namespace Plugins3Test
{
using System;
using System.ServiceModel;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
/// <summary>
/// PostContactUpdate Plugin.
/// Fires when the following attributes are updated:
/// All Attributes
/// </summary>
public class PostContactUpdate: Plugin
{
/// <summary>
/// Initializes a new instance of the <see cref="PostContactUpdate"/> class.
/// </summary>
public PostContactUpdate()
: base(typeof(PostContactUpdate))
{
base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>(40, "Update", "contact", new Action<LocalPluginContext>(ExecutePostContactUpdate)));
// Note : you can register for more events here if this plugin is not specific to an individual entity and message combination.
// You may also need to update your RegisterFile.crmregister plug-in registration file to reflect any change.
}
/// <summary>
/// Executes the plug-in.
/// </summary>
/// <param name="localContext">The <see cref="LocalPluginContext"/> which contains the
/// <see cref="IPluginExecutionContext"/>,
/// <see cref="IOrganizationService"/>
/// and <see cref="ITracingService"/>
/// </param>
/// <remarks>
/// For improved performance, Microsoft Dynamics CRM caches plug-in instances.
/// The plug-in's Execute method should be written to be stateless as the constructor
/// is not called for every invocation of the plug-in. Also, multiple system threads
/// could execute the plug-in at the same time. All per invocation state information
/// is stored in the context. This means that you should not use global variables in plug-ins.
/// </remarks>
protected void ExecutePostContactUpdate(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
// TODO: Implement your custom Plug-in business logic.
// Obtain the execution context from the service provider.
IPluginExecutionContext context = localContext.PluginExecutionContext;
IOrganizationService service = localContext.OrganizationService;
IServiceProvider serviceProvider = localContext.ServiceProvider;
ITracingService tracingService = localContext.TracingService;
// Obtain the target entity from the input parmameters.
//Entity contextEntity = (Entity)context.InputParameters["Target"];
Entity targetEntity = null;
targetEntity = (Entity)context.InputParameters["Target"];
Guid cid = targetEntity.Id;
ColumnSet cols = new ColumnSet("jobtitle");
Entity contact = service.Retrieve("contact", cid, cols);
contact.Attributes["jobtitle"] = "Sometitle";
service.Update(contact);
}
}
}
回答1:
it's happening because your plugin is executed when a contact is updated and the last line of your code update the contact again, this cause to call again the plugin ...
Then you have your infinite loop
You can prevent the loop using the IExecutionContext.Depth
property
http://msdn.microsoft.com/en-us/library/microsoft.xrm.sdk.iexecutioncontext.depth.aspx
However if you explain your requirement I think it's possible to find a solution.
回答2:
At first if IExecutionContext.Depth <= 1
seems like a great idea, but it can bite you if you have a different plugin that updates the contact. You should be using the SharedVariables of the plugin context.
Something like this should work:
Add this declaration to the plugin class as a class level field:
public static readonly Guid HasRunKey = new Guid("{6339dc20-01ce-4f2f-b4a1-0a1285b65bff}");
And add this as the first step of your plugin:
if(context.SharedVariables.ContainsKey[HasRunKey]){
return;
}else{
context.SharedVariables.Add(HasRunKey);
// Proceed with plugin execution
}
回答3:
**I went through a lot of trial and error. I don't know why plugin context does not work but this works but the parentcontext works. This (workaround?) works :) **
if (this.Context.ParentContext != null && this.Context.ParentContext.ParentContext != null)
{
var assemblyName = Assembly.GetExecutingAssembly().GetName().Name;
if (!this.Context.ParentContext.ParentContext.SharedVariables.Contains(assemblyName))
{
this.Context.ParentContext.ParentContext.SharedVariables.Add(assemblyName, true.ToString() );
}
else
{
// isRecursive = true;
return;
}
}
回答4:
Your plugin is updating the "jobtitle" field, I'm not sure if this plugin is being triggered by all contact updates, or you have set some FilteringAttributes to it in the Registerfile.crmregister Plugin's definition. By excluding the "jobtitle" field from the attributes that trigger this plugin you can solve your issue.
来源:https://stackoverflow.com/questions/18106926/microsoft-crm-plugin-infinite-loop