【问题标题】:Dynamics 365 CRM Online - Plugin Only Performs Update Every Other Time it is TriggeredDynamics 365 CRM Online - 插件仅在触发时每隔一次执行更新
【发布时间】:2018-06-19 14:12:32
【问题描述】:

更新 我从这个论坛以及 Dynamics 论坛中提取了一些信息,并且我的代码可以正常工作。我的代码中的主要问题是我只查看了 preImage,但在大多数情况下,三个值之一将被更新,这意味着我无法定位该特定字段的 preImage。我将逻辑更改为使用 Collection 属性(更新的值)如果它已更新,但如果它没有更新则使用 PreImage 值 - 这使得代码工作,并且每次都会触发更新 - 不再需要触发插件两次!这是更新后的代码 - 它比原始代码更高效、更简洁(向下滚动以查看旧/非工作代码)。我还添加了一些 cmets 使其更容易理解。感谢所有人的帮助(无论是在 SO 上,还是在 Dynamics 论坛上!)

using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Crm.Sdk.Messages;
using System.ServiceModel;
using System.Data.SqlClient;
using System.Threading.Tasks;

namespace CLIENTNTE
{
    public class NTEExceedance : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = factory.CreateOrganizationService(context.UserId);
            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));


            Decimal nte_percent = 0;
            Decimal subtotalDecimal = 0;
            Decimal nteDecimal = 0;
            Decimal amountDiffDecimal = 0;
            Decimal percentDifference = 0;
            try
            {

                if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
                {
                    Entity entity = (Entity)context.InputParameters["Target"];
                    //if entity is not Work Order, return.  Prevents plugin firing on wrong entity (in case of wrong registration in plugin registration tool)
                    if (entity.LogicalName != "msdyn_workorder")
                    {
                        return;
                    }
                    //get preimage of WO Entity
                    Entity preMessageImage = (Entity)context.PreEntityImages["WONTEPreImage"];

                    //logic for when updated attribute is NTE Amount
                    if (entity.Attributes.Contains("CLIENT_nteamount") == true)
                    {
                        nteDecimal = entity.GetAttributeValue<Money>("CLIENT_nteamount").Value;
                    }
                    else
                    {
                        nteDecimal = preMessageImage.GetAttributeValue<Money>("CLIENT_nteamount").Value;
                    }
                    //logic for when updated attribute is NTE Percent
                    if (entity.Attributes.Contains("CLIENT_ntepercent") == true)
                    {
                        nte_percent = entity.GetAttributeValue<Decimal>("CLIENT_ntepercent");
                    }
                    else
                    {
                        nte_percent = preMessageImage.GetAttributeValue<Decimal>("CLIENT_ntepercent");
                    }
                    //logic for when updated attribute is Estimate Subtotal Amount
                    if (entity.Attributes.Contains("msdyn_estimatesubtotalamount") == true)
                    {
                        subtotalDecimal = entity.GetAttributeValue<Money>("msdyn_estimatesubtotalamount").Value;
                    }
                    else
                    {
                        subtotalDecimal = preMessageImage.GetAttributeValue<Money>("msdyn_estimatesubtotalamount").Value;
                    }

                    //calculation of Amount Difference, and Percent Difference
                    amountDiffDecimal = (subtotalDecimal - nteDecimal);
                    percentDifference = ((amountDiffDecimal / nteDecimal) * 100);

                    //Comparison logic to update the NTE Exceeded flag
                    if (percentDifference > nte_percent)
                    {
                        entity["CLIENT_nteexceeded"] = true;
                    }
                    if (percentDifference <= nte_percent)
                    {
                        entity["CLIENT_nteexceeded"] = false;
                    }
                }
            }
            catch (FaultException<OrganizationServiceFault> e)
            {
                //write errors to the CRM Plugin Trace Log
                tracingService.Trace("CLIENTPlugin - Update NTEExceededNonCalc: {0}", e.ToString());
                //Throw error through UI
                throw new InvalidPluginExecutionException("Error, Please See Plugin Log");
            }
        }
    }
}

原帖 再来一次!昨天,我意识到我不使用 PreImage 来获取未包含在更新的属性集合中的值的方法中的错误 - SCORE!现在,插件工作,但它只在我触发插件时才工作。

所以,似乎插件实际上正在触发(我可以在设置 > 插件配置文件中看到插件配置文件),但没有执行我需要的更新,直到我第二次触发插件。这似乎发生在我正在监听的所有 3 个属性上,并且每个属性都需要更新两次(例如,如果我更新属性 1,插件不会更新我的值,如果我再更新属性 2,插件仍然不会更新我的值,直到我再次重新更新属性 1 或属性 2)。当我分析/调试我的代码并逐步执行它时,我可以看到 if 语句被命中,并且更新实体字段的代码行也正在执行 - 但无论出于何种原因,它都没有设置值 ( CLIENT_nteexceeded = true or false) 直到我第二次触发它。如果它根本不更新实体记录值会更有意义,而且我错过了某种类型的“更新”消息(我玩过 service.Entity.Update() 但它似乎没有应用到这个插件)

我对 CRMDEV 还是比较陌生,所以请原谅这个愚蠢的问题。这对我来说似乎是一个非常愚蠢的问题,而且它一定是我错过的一些小问题。关于为什么这会迫使我触发两次代码以执行更新的任何想法?

这是插件步骤的配置。这三个过滤器属性是代码中引用的那些。同样,插件工作正常,只是不会每次都更新记录。

下面的代码(删除了对客户名称的引用)

using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Crm.Sdk.Messages;
using System.ServiceModel;
using System.Data.SqlClient;
using System.Threading.Tasks;

namespace CLIENTNTE
{
    public class NTEExceedance : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = factory.CreateOrganizationService(context.UserId);
            //Extract the tracing service for use in debugging sandboxed plug-ins.
            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

            Money subtotal = null;
            Money nte = null;
            Decimal nte_percent = 0;
            Decimal subtotalDecimal = 0;
            Decimal nteDecimal = 0;
            Decimal amountDiffDecimal = 0;
            Decimal percentDifference = 0;
            try
            {

                if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
                {
                    Entity entity = (Entity)context.InputParameters["Target"];
                    if (entity.LogicalName == "msdyn_workorder")
                    {
                        //code fires onChange of NTE Amount (same logic will apply to NTE % and Est Subtotal Amount)
                        if (entity.Attributes.Contains("CLIENT_nteamount") == true)
                        {
                            //String NewValue = FieldValue(service, new Guid(entity["msdyn_workorderid"].ToString()));
                            // String NewSubTotal = FieldValue(service, new Guid(entity["msdyn_workorderid"].ToString()), entity["msdyn_estimatesubtotalamount"].ToString());
                            //String NewNTE = FieldValue(service, new Guid(entity["msdyn_workorderid"].ToString()), entity["CLIENT_nteamount"].ToString());
                            //String Newpercent = FieldValue(service, new Guid(entity["msdyn_workorderid"].ToString()), entity["CLIENT_ntepercent"].ToString());
                            if (context.PreEntityImages.Contains("WONTEPreImage") && context.PreEntityImages["WONTEPreImage"] is Entity)
                            {
                                Entity preMessageImage = (Entity)context.PreEntityImages["WONTEPreImage"];
                                // get topic field value before database update perform
                                //pretopic = (String)preMessageImage.Attributes["subject"];
                                subtotal = (Money)preMessageImage.Attributes["msdyn_estimatesubtotalamount"];
                                nte = (Money)preMessageImage.Attributes["CLIENT_nteamount"];
                                nte_percent = (Decimal)preMessageImage.Attributes["CLIENT_ntepercent"];
                            }
                            //old way of trying to get values NON IMAGE
                            //subtotal = (Money)entity.Attributes["msdyn_estimatesubtotalamount"];
                            //nte = (Money)entity.Attributes["CLIENT_nteamount"];
                            //nte_percent = (Decimal)entity.Attributes["CLIENT_ntepercent"];

                            subtotalDecimal = subtotal.Value;
                            nteDecimal = nte.Value;
                            amountDiffDecimal = (subtotalDecimal - nteDecimal);
                            percentDifference = ((amountDiffDecimal / nteDecimal) * 100);
                            if (percentDifference > nte_percent)
                            {
                                //know this snippet works
                                entity["CLIENT_nteexceeded"] = true;
                            }
                            if (percentDifference <= nte_percent)
                            {
                                //know this snippet works
                                entity["CLIENT_nteexceeded"] = false;
                            }
                        }
                        if (entity.Attributes.Contains("CLIENT_ntepercent") == true)
                        {
                            if (context.PreEntityImages.Contains("WONTEPreImage") && context.PreEntityImages["WONTEPreImage"] is Entity)
                            {
                                Entity preMessageImage = (Entity)context.PreEntityImages["WONTEPreImage"];
                                // get topic field value before database update perform
                                //pretopic = (String)preMessageImage.Attributes["subject"];
                                subtotal = (Money)preMessageImage.Attributes["msdyn_estimatesubtotalamount"];
                                nte = (Money)preMessageImage.Attributes["CLIENT_nteamount"];
                                nte_percent = (Decimal)preMessageImage.Attributes["CLIENT_ntepercent"];
                            }

                            //old way of trying to get values NON IMAGE
                            //subtotal = (Money)entity.Attributes["msdyn_estimatesubtotalamount"];
                            //nte = (Money)entity.Attributes["CLIENT_nteamount"];
                            //nte_percent = (Decimal)entity.Attributes["CLIENT_ntepercent"];
                            subtotalDecimal = subtotal.Value;
                            nteDecimal = nte.Value;
                            amountDiffDecimal = (subtotalDecimal - nteDecimal);
                            percentDifference = ((amountDiffDecimal / nteDecimal) * 100);

                            if (percentDifference > nte_percent)
                            {
                                //know this snippet works
                                entity["CLIENT_nteexceeded"] = true;
                            }
                            if (percentDifference <= nte_percent)
                            {
                                //know this snippet works
                                entity["CLIENT_nteexceeded"] = false;
                            }
                        }
                        if (entity.Attributes.Contains("msdyn_estimatesubtotalamount") == true)
                        { 
                            if (context.PreEntityImages.Contains("WONTEPreImage") && context.PreEntityImages["WONTEPreImage"] is Entity)
                            {
                                Entity preMessageImage = (Entity)context.PreEntityImages["WONTEPreImage"];
                                subtotal = (Money)preMessageImage.Attributes["msdyn_estimatesubtotalamount"];
                                nte = (Money)preMessageImage.Attributes["CLIENT_nteamount"];
                                nte_percent = (Decimal)preMessageImage.Attributes["CLIENT_ntepercent"];
                            }

                            //old way of trying to get values NON IMAGE
                            //subtotal = (Money)entity.Attributes["msdyn_estimatesubtotalamount"];
                            //nte = (Money)entity.Attributes["CLIENT_nteamount"];
                            //nte_percent = (Decimal)entity.Attributes["CLIENT_ntepercent"];

                            subtotalDecimal = subtotal.Value;
                            nteDecimal = nte.Value;
                            amountDiffDecimal = (subtotalDecimal - nteDecimal);
                            percentDifference = ((amountDiffDecimal / nteDecimal) * 100);

                            if (percentDifference > nte_percent)
                            {
                                //know this snippet works
                                entity["CLIENT_nteexceeded"] = true;
                            }
                            if (percentDifference <= nte_percent)
                            {
                                //know this snippet works
                                entity["CLIENT_nteexceeded"] = false;
                            }

                        }

                    }
                }

            }
            catch (FaultException<OrganizationServiceFault> e)
            {
                tracingService.Trace("CLIENTPlugin - Update NTEExceededNonCalc: {0}", e.ToString());
                throw e;
            }
        }
    }

}

【问题讨论】:

  • 只是一个疯狂的猜测。尝试将执行管道作为 PreOperation 而不是 PreValidation 并查看..
  • 感谢@ArunVinoth。我不知道为什么,但是当我更新我的步骤以使用 PreOperation(或其他任何东西)时,我开始在 CRM 中遇到错误。我想我必须注销并重新注册整个事情才能更改执行管道?奇怪,但我昨天正在尝试这个确切的东西,并遇到了同样的问题。我今天不得不删除并重新添加,但没有将其切换到 PreOp。我将在重新删除后立即尝试
  • 是的,只是重新添加了插件并将其设置为 PreOperation,它仍然表现出相同的行为。多么令人沮丧!我不知道为什么这个东西不会触发更新,除非它第二次执行插件....
  • 在您的问题中尽量简洁...当您寻求帮助时,少即是多。
  • 感谢@Daryl 的建议。我总是试图平衡提供足够的信息和太少的信息。我觉得我总是必须在问题中提供尽可能多的信息,以便为那些善意提供帮助的人描绘整个画面。以后我会努力删掉多余的文字。

标签: c# dynamics-crm microsoft-dynamics dynamics-crm-online


【解决方案1】:

我将帮助您了解 CRM 执行管道的工作原理。然后,您可以在 trace/Audit/profiler 的帮助下进行故障排除,以确定失败的位置。

基本上,您正在拦截在预验证/预操作阶段的数据库事务之前从 CRM UI 发生的service.Update() 平台调用。然后根据业务需要进行数据操作并在目标实体本身中设置额外的属性值。这避免了另一个显式的额外service.Update() 调用和循环死锁。

如果有任何异常,您正在登录跟踪并抛出相同的内容。我建议将其更改为InvalidPluginExecutionException,您将在 UI 弹出窗口中看到它。这将回滚事务,这意味着数据不会被保存。

此外,为了更好地理解 - 记录每个条件语句、变量值等,以查看错误的确切跟踪日志。

【讨论】:

  • 谢谢阿伦。我将你的一些信息与 Dynamics 论坛上给我的一些东西结合起来,我的插件就可以工作了。事实证明,我需要检查 Attributes.Contains,然后如果该属性未包含在集合中,则从 PreImage 获取值。如果该属性包含在集合中(已更新),我将使用该值。将基本逻辑放入我的代码中解决了我的问题。我也确实使用了 Invalid PluginExecutionException 通过 UI 弹出错误 - 以及跟踪服务将问题写回 CRM 日志。
  • 另外,我之前曾尝试将每个变量写入表单上的变量以及通过跟踪服务。但我无法让它发挥作用。对于这个(诚然小而不复杂)插件,我不再需要这样做了,但我知道对于我将遇到的更复杂的工作,我可以而且当然应该尝试写出变量值以便我可以跟踪其中。我还花了很多时间在调试器中通过代码来跟踪变量 - 但我同意,输出这些变量会很有帮助。
  • Arun,检查原始帖子(现在已编辑)以获取最终有效的代码。感谢您的所有帮助 - 非常感谢!
  • @BrianFrick 想提一下,这个答案stackoverflow.com/a/50916346/7920473 中的最后两行代码在条件运算符的帮助下也是如此。
  • 谢谢阿伦。我现在看到了,非常有帮助!
【解决方案2】:

更新/回答我从这个论坛以及 Dynamics 论坛中提取了一些信息,并且我的代码可以正常工作。我的代码中的主要问题是我只查看了 preImage,但在大多数情况下,三个值之一将被更新,这意味着我无法定位该特定字段的 preImage。我更改了我的逻辑以使用 Collection 属性(更新的值),如果它已更新,但如果它没有更新,则使用 PreImage 值 - 这使得代码工作,并且每次都会触发更新 - 不再需要触发插件两次!这是更新后的代码 - 它比原始代码更有效和简洁(向下滚动以查看旧/非工作代码)。我还添加了一些 cmets 使其更容易理解。感谢所有人的帮助(无论是在 SO 上,还是在 Dynamics 论坛上!)

using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Crm.Sdk.Messages;
using System.ServiceModel;
using System.Data.SqlClient;
using System.Threading.Tasks;

namespace CLIENTNTE
{
    public class NTEExceedance : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = factory.CreateOrganizationService(context.UserId);
            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));


            Decimal nte_percent = 0;
            Decimal subtotalDecimal = 0;
            Decimal nteDecimal = 0;
            Decimal amountDiffDecimal = 0;
            Decimal percentDifference = 0;
            try
            {

                if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
                {
                    Entity entity = (Entity)context.InputParameters["Target"];
                    //if entity is not Work Order, return.  Prevents plugin firing on wrong entity (in case of wrong registration in plugin registration tool)
                    if (entity.LogicalName != "msdyn_workorder")
                    {
                        return;
                    }
                    //get preimage of WO Entity
                    Entity preMessageImage = (Entity)context.PreEntityImages["WONTEPreImage"];

                    //logic for when updated attribute is NTE Amount
                    if (entity.Attributes.Contains("CLIENT_nteamount") == true)
                    {
                        nteDecimal = entity.GetAttributeValue<Money>("CLIENT_nteamount").Value;
                    }
                    else
                    {
                        nteDecimal = preMessageImage.GetAttributeValue<Money>("CLIENT_nteamount").Value;
                    }
                    //logic for when updated attribute is NTE Percent
                    if (entity.Attributes.Contains("CLIENT_ntepercent") == true)
                    {
                        nte_percent = entity.GetAttributeValue<Decimal>("CLIENT_ntepercent");
                    }
                    else
                    {
                        nte_percent = preMessageImage.GetAttributeValue<Decimal>("CLIENT_ntepercent");
                    }
                    //logic for when updated attribute is Estimate Subtotal Amount
                    if (entity.Attributes.Contains("msdyn_estimatesubtotalamount") == true)
                    {
                        subtotalDecimal = entity.GetAttributeValue<Money>("msdyn_estimatesubtotalamount").Value;
                    }
                    else
                    {
                        subtotalDecimal = preMessageImage.GetAttributeValue<Money>("msdyn_estimatesubtotalamount").Value;
                    }

                    //calculation of Amount Difference, and Percent Difference
                    amountDiffDecimal = (subtotalDecimal - nteDecimal);
                    percentDifference = ((amountDiffDecimal / nteDecimal) * 100);

                    //Comparison logic to update the NTE Exceeded flag
                    if (percentDifference > nte_percent)
                    {
                        entity["CLIENT_nteexceeded"] = true;
                    }
                    if (percentDifference <= nte_percent)
                    {
                        entity["CLIENT_nteexceeded"] = false;
                    }
                }
            }
            catch (FaultException<OrganizationServiceFault> e)
            {
                //write errors to the CRM Plugin Trace Log
                tracingService.Trace("CLIENTPlugin - Update NTEExceededNonCalc: {0}", e.ToString());
                //Throw error through UI
                throw new InvalidPluginExecutionException("Error, Please See Plugin Log");
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 2018-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-22
    • 1970-01-01
    • 1970-01-01
    • 2017-07-09
    相关资源
    最近更新 更多