简体   繁体   English

Dynamics 365 CRM Online-插件仅每隔一次触发执行更新

[英]Dynamics 365 CRM Online - Plugin Only Performs Update Every Other Time it is Triggered

Update I pulled some information from this forum, as well as the Dynamics forum, and I got my code working. 更新我从该论坛以及Dynamics论坛中获取了一些信息,并且我的代码可以正常工作。 The main issue in my code was that I was only looking at the preImage, but in most scenarios, one of the three values will be updated, meaning that I cannot target the preImage of that particular field. 代码中的主要问题是我只查看了preImage,但是在大多数情况下,这三个值之一将被更新,这意味着我无法针对该特定字段的preImage。 I changed my logic to use the Collection attribute (updated value) if it was updated, but to use the PreImage value if it wasn't updated - and this makes the code work, and the updates fire every time - no more need to trigger the plugin twice! 我更改了逻辑以使用Collection属性(更新值)(如果已更新),但是使用PreImage值(如果未更新)-这使代码起作用,并且每次都会触发更新-不再需要触发插件两次! Here is the updated code - which is much more efficient and concise than the original code (scroll down to see the old/non working code). 这是更新后的代码-比原始代码更有效,更简洁(向下滚动以查看旧的/无效的代码)。 I have also added some comments to make it a little easier to understand. 我还添加了一些评论,以使其更易于理解。 Thanks to all for the help (both here on SO, and on Dynamics forums!) 感谢所有人的帮助(无论是在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");
            }
        }
    }
}

Original Post Back at it again! 原帖再回来一次! Yesterday, I realized the error in my ways of not using a PreImage to get the values that were not being included in the updated attributes collection - SCORE! 昨天,我意识到我不使用PreImage来获取未包含在更新的属性集合中的值的错误-SCORE! Now, the plugin works , but it only works every other time I trigger the plugin. 现在,该插件可以正常运行了 ,但是仅在我触发该插件时每隔一次它才能工作。

So, it seems the plugin is actually firing (I can see the plugin profile in Settings > plugin profiles), but is not performing the update that I need, until I trigger the plugin a second time. 因此,似乎插件实际上正在触发(我可以在“设置”>“插件配置文件”中看到插件配置文件),但是没有执行我需要的更新,直到第二次触发插件为止。 This seems to happen on all 3 attributes that I am listening for, and each of the attributes will need to be updated twice (as in, if I update Attribute 1, plugin doesn't update my value, if I then update attribute 2, plugin still doesn't update my value, until I re-update Attribute 1 or Attribute 2 again). 这似乎发生在我正在监听的所有3个属性上,并且每个属性都需要更新两次(例如,如果我更新了属性1,则插件不会更新我的值,如果我随后更新了属性2,插件仍然不会更新我的值,直到再次重新更新属性1或属性2为止)。 As I profile/debug my code and step through it, I can see that the if statements are being hit, and the line of code that updates the entity field is also being executed - but for whatever reason, it does not set the value (CLIENT_nteexceeded = true or false) until I trigger it for the second time. 在我分析/调试代码并逐步执行代码时,我可以看到if语句被命中,并且更新了实体字段的代码行也正在执行-但由于某种原因,它没有设置值( CLIENT_nteexceeded = true或false),直到我第二次触发它为止。 It would make a lot more sense if it just didn't update the entity record value at all, and I was missing some type of an 'update' message (I have played with service.Entity.Update() but it does not seem to apply to this plugin) 如果它根本不更新实体记录值,那将更有意义,而且我缺少某种类型的“更新”消息(我曾使用过service.Entity.Update(),但似乎没有应用于此插件)

I am still relatively new to CRMDEV, so please excuse the silly question. 我对CRMDEV还是比较陌生,所以请原谅这个愚蠢的问题。 This just seems like a really silly issue to me, and it's gotta be something small that I'm missing. 对我来说,这似乎是一个非常愚蠢的问题,这肯定是我所缺少的小事情。 Any thoughts as to why this is forcing me to trigger the code twice to get the update executed? 关于为什么这迫使我两次触发代码以执行更新的任何想法?

Here is the config of the plugin step. 这是插件步骤的配置。 The three filter attributes are those referenced in the code. 这三个过滤器属性是代码中引用的属性。 Again, plugin works fine, just doesn't update the record every time. 同样,插件工作正常,只是不会每次都更新记录。 在此处输入图片说明

Code Below (with references to Client's name removed) 以下代码(删除了对客户名称的引用)

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;
            }
        }
    }

}

I will help you to understand how CRM execution pipeline works. 我将帮助您了解CRM执行管道的工作方式。 Then you can troubleshoot with the help of trace/Audit/profiler to identify where it fails. 然后,您可以在trace / Audit / profiler的帮助下进行故障排除,以找出失败的地方。

Basically you are intercepting the service.Update() platform call happening from CRM UI just before the DB transaction in pre-validation/pre-operation stage. 基本上,您是在预验证/预操作阶段中,在DB事务之前拦截从CRM UI发生的service.Update()平台调用。 Then doing data manipulation based on business need & setting the extra attribute values in target entity itself. 然后根据业务需要进行数据处理,并在目标实体本身中设置额外的属性值。 This avoids another explicit extra service.Update() call & inturn cyclic deadlock. 这避免了另一个显式的额外service.Update()调用并反过来循环死锁。

If there's any exception, you are logging in trace & throwing the same. 如果有任何异常,则您正在登录跟踪并抛出该异常。 I would recommend to change this into InvalidPluginExecutionException which you will see in UI popup window. 我建议将其更改为InvalidPluginExecutionException ,您将在UI弹出窗口中看到该InvalidPluginExecutionException This will rollback the transaction, that means data won't be saved. 这将回滚事务,这意味着不会保存数据。

In addition, to understand better - log each conditional statement, variable values, etc to see the exact trace log of what went wrong. 此外,为了更好地理解-记录每个条件语句,变量值等,以查看发生问题的确切跟踪日志。

Update/Answer I pulled some information from this forum, as well as the Dynamics forum, and I got my code working. 更新/回答我从该论坛以及Dynamics论坛中获取了一些信息,并且我的代码可以正常工作。 The main issue in my code was that I was only looking at the preImage, but in most scenarios, one of the three values will be updated, meaning that I cannot target the preImage of that particular field. 代码中的主要问题是我只查看了preImage,但是在大多数情况下,这三个值之一将被更新,这意味着我无法针对该特定字段的preImage。 I changed my logic to use the Collection attribute (updated value) if it was updated, but to use the PreImage value if it wasn't updated - and this makes the code work, and the updates fire every time - no more need to trigger the plugin twice! 我更改了逻辑以使用Collection属性(更新值)(如果已更新),但是使用PreImage值(如果未更新)-这使代码起作用,并且每次都会触发更新-不再需要触发插件两次! Here is the updated code - which is much more efficient and concise than the original code (scroll down to see the old/non working code). 这是更新后的代码-比原始代码更有效,更简洁(向下滚动以查看旧的/无效的代码)。 I have also added some comments to make it a little easier to understand. 我还添加了一些评论,以使其更易于理解。 Thanks to all for the help (both here on SO, and on Dynamics forums!) 感谢所有人的帮助(无论是在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");
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM