简体   繁体   中英

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. 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. 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! 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!)

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! 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). 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. 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)

I am still relatively new to CRMDEV, so please excuse the silly question. 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. Then you can troubleshoot with the help of trace/Audit/profiler to identify where it fails.

Basically you are intercepting the service.Update() platform call happening from CRM UI just before the DB transaction in pre-validation/pre-operation stage. 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.

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. 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. 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. 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! 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!)

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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