在 Microsoft Dynamics CRM 2011 中如何防止没有 ExecutionContext.CallerOrigin 的无限循环?
在 Microsoft Dynamics CRM 4.0 中创建插件时,您可以使用以下命令来检查导致插件触发的事件的来源。
public void Execute(IPluginExecutionContext context)
{
if (context.CallerOrigin.GetType() == CallerOrigin.WebServiceApi.GetType())
{
return;
}
plugin code here...
}
这将允许您检查该操作是否是由表单中的用户、Web 服务或工作流程等引起的...
我有一个同步应用程序,它通过 WCF 创建和更新实体,并且不希望插件在以下情况下执行仅当用户编辑实体时才会发生这种情况(以防止同步过程中出现无限循环)。
IExecutionContext.CallerOrigin
已在 MS Dynamics CRM 2011 中删除,那么执行此操作的新方法是什么?
我在想可能有一种方法可以设置 IExecutionContext.CorrelationId 在 WCF 调用中,然后检查插件中的特定 Guid,但我还没有遇到任何运气。
When creating a plugin in Microsoft Dynamics CRM 4.0 you could use the following to check the origin of the event that caused the plugin to fire.
public void Execute(IPluginExecutionContext context)
{
if (context.CallerOrigin.GetType() == CallerOrigin.WebServiceApi.GetType())
{
return;
}
plugin code here...
}
This would allow you to check if the action was caused by a user in a form, by a web service or a workflow etc...
I have a syncing app that creates and updates entities via WCF, and do not want the plugin executing when this happens, only when users edit entities (to prevent infinite loops in the sync process).
IExecutionContext.CallerOrigin
has been removed in MS Dynamics CRM 2011, so what is the new way to do this?
I was thinking that there may be a way to set IExecutionContext.CorrelationId
in the WCF calls and then check for it the specific Guid in the plugin, but I haven't had any luck with this yet.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
虽然这似乎已经被问过一段时间了(我想OP现在已经找到了他的解决方案!)我最近发现它正在寻找类似的答案。需要进一步的研究才能找出我需要什么,因此我也会将其添加到此处,以供其他遇到它的人使用。
首先,如果您正在寻找它,该属性已过时。据说是因为它不可靠,但我们需要 MSCRM 4.0 中的 CallerOrigin 有几个原因。另一方面,也有一些方法可以解决这个问题:
防止无限循环(超过 2 个插件)
这就是我寻找 CallerOrigin 的原因以及我是如何遇到这个问题的。我只希望插件来自表单上的用户,而不是来自另一个插件(即异步进程/网络服务)时触发。就我而言,“超过 2 个插件”的区别非常重要,因为我无法使用 InputParameters 来解决问题。我的示例类似于以下内容:
更新“父”实体的插件。如果父实体上名为“状态”的选项集设置为“已批准”,我随后希望将所有子实体的状态也设置为“已批准”。
更新“子”实体的插件。如果子实体上名为“状态”的选项集设置为“已批准”,并且同一父实体的所有其他子实体都将此设置为“已批准”,我也需要将父实体上的状态更新为已批准。
如果您不采取保护措施,这会导致无限循环。您也不能使用InputParameters 来解决它。一个基本的解决方案是使用深度检查:
如果大于 1,则表示已被另一个插件/工作流调用。注意:如果您有一个触发初始更新的工作流程,您可能需要小心检查的值。
防止来自离线客户端的同步问题
我们获得了不同的属性来帮助我们区分这些问题。请改用这些:
根据来源做出不同的反应
好的,所以这是我们真正需要 CallerOrigin 的唯一场景。我认为您能够做到这一点的唯一方法是检查 PluginExecutionContext 本身的类型。我知道对于异步,它的类型是:
对于插件,它似乎是:
不确定来自外部源时它是什么,不幸的是,我目前没有任何可用的代码来测试和弄清楚这一点。除此之外,您可能需要检查:
我遇到的用于检测更新来源的唯一其他方法是使用表单上的自定义标志。 创建一个名为“OriginOfChange”(或类似名称)的选项集。
然后在更新期间更新实体集此字段。通过这种方式,您可以每次检查输入参数以查看更新来自何处。
如果您需要根据来源做出不同的反应,最后一种方法很可能是最安全的。
Although this seems to have been asked some time back (and I presume the OP has found his solution by now!) I came across it looking for a similar answer recently. It took further research to find out what I needed so for this reason I'll add it here too for anyone else that comes across it.
Firstly, if you are looking for it, this property has been made obsolete. Supposedly because it was unreliable, but there were a few reasons why we needed the CallerOrigin in MSCRM 4.0. On the other hand, there are ways around this becoming obsolete too:
Prevent infinite loops (over 2 plugins)
This was the reason I was looking for the CallerOrigin and how I came across this question. I only wanted the plugin to fire if it came from a user on the form, not from another plugin (i.e. asyc process/webservice). In my case the distinction of it being "over 2 plugins" is quite important, because I cannot use InputParameters to solve the problem. My example was similar to the following:
Update Plugin for "Parent" Entity. If optionset called "Status" on the parent entity was set to "Approved" I subsequently wanted to set a status on all the child entities to "Approved" as well.
Update Plugin for "Child" Entity. If the optionset called "Status" on the child entity was set to "approved", and all other children of the same parent has this set to "Approved" I needed to update the Status on the parent to approved as well.
This causes an infinite loop if you don't protect yourself against it. You also cannot use the InputParameters to solve it. One basic solution is to use depth checking:
If this is greater than 1 it has been called by another plugin/workflow. Note: If you have a workflow that is triggering the initial update you might want to be careful with what value you are checking for.
Prevent syncing issues from an offline client
We've been given different properties to help us distinguish these ones. Use these instead:
Reacting differently depending on what the origin is
OK, so this is the only scenario where we really do need the CallerOrigin. The only way I think you'd be able to do this is by checking the type of the PluginExecutionContext itself. I know for async it's the type:
and for plugins it seems to be:
Not sure what it is when coming from an external source, I unfortunately don't have any code available at the moment to test and figure this out. Outside of all that you would probably have to check:
The only other method I've come across for detecting where the update came from is using a custom flag on the form. So you could create an OptionSet called "OriginOfChange" (or something similar) with the options
Then what ever updates the entity sets this field during the update. In this way you could check the Input Parameters each time to see where the update has come from.
This last method is most likely the safest to employ if you need to react differently depending on the source.
此线程的解决方案是“只需检查 context.depth 属性,如果它大于 1 返回”
它对于我更新其中的实体的更新插件来说工作得非常好,导致插件被触发两次,但在第二次时,它检查了深度并退出。
更新
到目前为止,最安全的方法是使用共享不过,变量而不是插件深度。如果唯一检查的是插件深度,那么每当另一个插件触发另一个插件时,它都不会执行,因为它的深度为 2,即使这是该插件第一次为 Update 事件触发。
This thread's solution is to "Just check for context.depth property, if it's greater then 1 return"
It worked perfectly fine for my update plugin where I was updating the entity within it, causing the plugin to get fired twice, but on the second time, it checked for the depth and exited.
Update
By far the safest method is to use the shared variables rather than plugin depth though. If the only thing that is checked is the plugin depth, then anytime another plugin triggers another plugin, it won't execute because it's depth is 2, even though it is the first time the plugin has fired for the Update event.
您查看过 IPluginExecutionContext.InputParameters 内部吗?
另一种选择是修改您的插件,使其在没有更改的情况下不更新任何内容,这将防止无限循环的可能性。
Have you looked inside the IPluginExecutionContext.InputParameters?
The other option would be to modify your plugin to not update anything if there were no changes, which would prevent the possibility of the infinite loop.
深度是执行的深度,而不是递归的深度。您可以收到深度> 1 第一次执行你的插件时。把它想象成执行管道中的一个级别(实际上是执行堆栈深度),有人先得到它,当执行通过时深度增加1,所以下一个在队列中做一些其他操作,然后再传递它到管道增量 +1 深度,现在 Dynamics 执行您的插件,您的深度将为 3(初始 1 [+1|+1])。 CRM 2011 本地部署默认限制为 8,在线深度限制为 16。
因此,通过使用您只是假设它的深度来预防递归,您无法断言它。
我的
2美分,
此致
埃里克·阿瑞安
The Depth is of execution, not recursion. You can recieve a Depth > 1 the first time your plugin got executed. Think of it as a Level in the execution pipeline (actually is the execution stack depth), some one got it first, when execution is passed the Depth is increased by 1, so the next in line do some other operation and before passing it again to the pipe increments +1 depth, now Dynamics executes your plugin, your depth would be 3 (Initial 1 [+1|+1]). CRM 2011 on-premise is limited by default to 8 and on-line is limited to a depth of 16.
So, recursion prevention by using the Depth you are just ASSUMING it, you can not assert it.
MSDN IExecutionContext.Depth Property
My 2 Cents,
Best Regards
Eric Arean