【问题标题】:How to prevent infinite looping without ExecutionContext.CallerOrigin in Microsoft Dynamics CRM 2011?如何在 Microsoft Dynamics CRM 2011 中防止没有 ExecutionContext.CallerOrigin 的无限循环?
【发布时间】:2011-05-16 07:27:33
【问题描述】:

在 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 中删除,那么执行此操作的新方法是什么?

我在想可能有一种方法可以在 WCF 调用中设置 IExecutionContext.CorrelationId,然后检查插件中的特定 Guid,但我还没有运气。

【问题讨论】:

    标签: c# wcf dynamics-crm infinite-loop dynamics-crm-2011


    【解决方案1】:

    虽然这似乎已经被问过一段时间了(我认为 OP 现在已经找到了他的解决方案!)我最近遇到了它,正在寻找类似的答案。需要进一步研究才能找到我需要的东西,因此我也会在此处添加它,以供遇到它的其他人使用。

    首先,如果您正在寻找它,此属性已过时。可能是因为它不可靠,但我们需要 MSCRM 4.0 中的 CallerOrigin 有几个原因。另一方面,也有一些方法可以解决这个问题:

    防止无限循环(超过 2 个插件)

    这就是我寻找 CallerOrigin 的原因以及我是如何遇到这个问题的。我只希望插件来自表单上的用户,而不是来自另一个插件(即 asyc 进程/webservice)。在我的情况下,它是“超过 2 个插件”的区别非常重要,因为我不能使用 InputParameters 来解决问题。我的示例类似于以下内容:

    • “父”实体的更新插件。如果父实体上名为“状态”的选项集设置为“已批准”,我随后想将所有子实体的状态也设置为“已批准”。

    • “子”实体的更新插件。如果子实体上名为“状态”的选项集设置为“已批准”,并且同一父实体的所有其他子实体都将此设置为“已批准”,我需要将父实体上的状态也更新为已批准。

    如果您不保护自己免受它的侵害,这会导致无限循环。您也不能使用 InputParameters 来解决它。一种基本的解决方案是使用深度检查:

    context.PluginExecutionContext.Depth
    

    如果大于 1,则它已被另一个插件/工作流程调用。注意:如果您有一个触发初始更新的工作流,您可能需要注意检查的值。

    防止来自离线客户端的同步问题

    我们获得了不同的属性来帮助我们区分这些属性。改用这些:

    context.PluginExecutionContext.IsExecutingOffline
    context.PluginExecutionContext.IsOfflinePlayback
    

    根据来源的不同做出不同的反应

    好的,所以这是我们真正需要 CallerOrigin 的唯一场景。我认为您能够做到这一点的唯一方法是检查 PluginExecutionContext 本身的类型。我知道异步它的类型:

    Microsoft.Crm.Asynchronous.AsyncExecutionContext
    

    对于插件来说,它似乎是:

    Microsoft.Crm.Extensibility.PipelineExecutionContext
    

    不确定来自外部来源是什么,遗憾的是,我目前没有任何代码可以测试和解决这个问题。除了您可能需要检查的所有内容之外:

    PluginExecutionContext.ParentContext
    

    我遇到的用于检测更新来自何处的唯一其他方法是在表单上使用自定义标志。因此,您可以使用选项创建一个名为“OriginOfChange”(或类似名称)的选项集

    • CRM 表单(JavaScript onsave)
    • 工作流程
    • 插件

    然后在更新期间更新实体会设置此字段。通过这种方式,您可以每次检查输入参数以查看更新的来源。

    如果您需要根据来源做出不同的反应,那么最后一种方法很可能是最安全的方法。

    【讨论】:

    • 这是最好的答案,尽管当您断言如果深度大于 1 时,您在技术上是不正确的,该插件正在被另一个插件调用。如果工作流导致插件触发,则深度为 2,如果一系列链接在一​​起的工作流导致插件触发,则深度将等于链接在一起的工作流数量 + 1。
    • @JosephDuty 感谢您的反馈,非常好。我将更新问题以反映这一点。
    • 为了补充最后两点,我在插件/工作流程和深度检查方面添加了一些额外的细节。事后看来(还有几年的经验!)我认为您在为此目的使用深度检查时可能需要小心。我建议的最后一种方法是最好的(在我看来)使用。我已将原始答案的症结留在原处,因为我认为不应该对其进行太多编辑。
    【解决方案2】:

    This 线程的解决方案是“只检查 context.depth 属性,如果它大于 1,则返回”

    它对我的更新插件非常有效,我在其中更新实体,导致插件被触发两次,但第二次,它检查深度并退出。

    更新

    到目前为止,最安全的方法是使用 shared variables 而不是插件深度。如果唯一检查的是插件深度,那么任何时候另一个插件触发另一个插件,它都不会执行,因为它的深度是 2,即使这是插件第一次为 Update 事件触发。

    【讨论】:

    • 我一直认为这在您拥有更新实体并触发代码的工作流或插件的情况下变得不可靠。例如。如果您的插件旨在将 new_fieldA 添加到 new_fieldB 并填充 new_fieldTotal 并且如果 new_fieldA 或 new_fieldB 更改它应该触发,那么 Depth 在运行时通过 UI 更改为 1。我认为如果另一个插件或工作流因此更改 new_fieldA 或 new_fieldB触发你的插件然后Depth > 1。我可能应该测试一下,但我在这里评论以防其他人已经拥有...... :)
    【解决方案3】:

    您是否查看过 IPluginExecutionContext.InputParameters 内部?

    另一种选择是修改您的插件,如果没有更改,则不更新任何内容,这将防止无限循环的可能性。

    【讨论】:

    • 如果更改是由指定用户发起的,我可能不必更新,因为同步工具会进行更改。我真的想防止双重同步而不是无限循环:)因为我可以在同步工具中停止循环
    • context.InitiatingUserId 为您提供 guid id。就我而言,我想从触发插件中排除单个用户,这成功了。
    【解决方案4】:

    深度是执行,而不是递归。您可以在插件第一次执行时收到深度 > 1。把它想象成执行管道中的一个Level(实际上是执行堆栈深度),有人先得到它,当执行通过时Depth增加1,所以下一个行做一些其他操作,然后再通过它管道增加 +1 深度,现在 Dynamics 执行您的插件,您的深度将为 3(初始 1 [​​+1|+1])。 CRM 2011 on-premise 默认限制为 8,在线限制为 16。

    所以,使用深度来防止递归你只是假设它,你不能断言它。

    MSDN IExecutionContext.Depth Property

    我的 2 美分, 最好的祝福 埃里克·阿雷恩

    【讨论】:

    • 尽管我同意您在技术上是正确的,但就所提出的问题而言,您的回答与上下文无关。如果这是对先前答案的评论,我可能会反对。
    猜你喜欢
    • 1970-01-01
    • 2018-09-22
    • 1970-01-01
    • 2013-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-01
    相关资源
    最近更新 更多