none
CRM Plugin - doesn't appear to do anything

    Question

  • I have written my first plug-in, but it doesn't appear to do anything.

    I have a field on the quote form that I want updating with the parentproduct names from the products that are on the quote when the quote is activated, here is the code:

    namespace Plugin_Project
    {
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using Microsoft.Xrm.Sdk;
        using System.ServiceModel;
        using System.Threading.Tasks;
        using Microsoft.Xrm.Sdk.Query;
    
        public class PreQuoteUpdate: Plugin
        {
    
            public PreQuoteUpdate()
                : base(typeof(PreQuoteUpdate))
            {
                base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>(20, "Update", "quote", new Action<LocalPluginContext>(ExecutePreQuoteUpdate)));
    
            }
    
            protected void ExecutePreQuoteUpdate(LocalPluginContext localContext)
            {
                if (localContext == null)
                {
                    throw new ArgumentNullException("localContext");
                }
    
                IPluginExecutionContext context = localContext.PluginExecutionContext;
                IOrganizationService service = localContext.OrganizationService;
                ITracingService tracingService = localContext.TracingService;
                IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)localContext.ServiceProvider.GetService(typeof(IOrganizationServiceFactory));
    
                Entity entity = null;
    
                    // linq QUERY
                    Quote currentQuote = entity.ToEntity<Quote>();
                    using (GeneratedCode orgcontext = new GeneratedCode(service))
                    {
                        var _results = (from quote in orgcontext.QuoteSet
                                        join qd in orgcontext.QuoteDetailSet on quote.QuoteId equals qd.QuoteId.Id
                                        join prod in orgcontext.ProductSet on qd.sp_SellingProductId.Id equals prod.ProductId
                                        where (quote.Name == "QUO-01694-D9H2")
                                        select prod.orb_ParentProductid).Distinct();
    
                        var _txttowrite = "";
                        foreach (var x in _results)
                        {
                            _txttowrite = x + ", ";
                        }
    
                        currentQuote.ancon_quoteproducts = _txttowrite;
                    }
            }
        }
    }
    

    For testing purposes I have got it to look up the products on one specific quote.

    I am new to this plugin development so struggling a little.

    regards,

    Matt

    Thursday, July 10, 2014 2:40 PM

Answers

  • Hello Matt,

    I build the C# code, tested and it's working just fine. Take a look at how I did it:

    using System;
    using System.ServiceModel;
    using System.Linq;
    using Microsoft.Xrm.Sdk;
    using Microsoft.Xrm.Sdk.Query;
    
    namespace ClassLibrary1
    {
        public class QuoteProductsOnAField : IPlugin
        {
            public void Execute(IServiceProvider serviceProvider)
            {
                ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
                IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
    
                if (context.InputParameters.Contains("EntityMoniker") && context.InputParameters["EntityMoniker"] is EntityReference)
                {
                    EntityReference entity = (EntityReference)context.InputParameters["EntityMoniker"];
    
                    if (entity.LogicalName != "quote")
                        return;
    
                    IOrganizationServiceFactory serviceFactory =
                        (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                    IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
    
                    try
                    {
                        // Your Business Logic
    
                        using (ServiceContext svcContext = new ServiceContext(service))
                        {
                            var retrievedProducts = from p in svcContext.ProductSet
                                                    join qd in svcContext.QuoteDetailSet
                                                    on p.ProductId equals qd.ProductId.Id
                                                    where qd.QuoteId.Id == entity.Id
                                                    select new
                                                    {
                                                        product_name = p.Name
                                                    };
    
                            if (retrievedProducts != null)
                            {
                                var products = String.Empty;
    
                                foreach (var item in retrievedProducts)
                                {
                                    if (String.IsNullOrEmpty(products))
                                    {
                                        products = item.product_name;
                                    }
                                    else
                                    {
                                        products += ", " + item.product_name;
                                    }
                                }
    
                                Quote currentQuote = (Quote)service.Retrieve(Quote.EntityLogicalName, entity.Id, new ColumnSet(false));
    
                                currentQuote.new_Products = products;
    
                                service.Update(currentQuote);
                            }
                        }
                    }
    
                    catch (FaultException<OrganizationServiceFault> ex)
                    {
                        throw new InvalidPluginExecutionException("An error occurred in MyPlug-in.", ex);
                    }
    
                    catch (Exception ex)
                    {
                        tracingService.Trace("MyPlugin: {0}", ex.ToString());
                        throw;
                    }
                }
            }
        }
    }

    Register Steps for both "SetState" and "SetStateDynamicEntity" messages. Here is an example:


    Hope it helps,

    Elvis


    Saturday, July 12, 2014 4:55 PM

All replies

  • Hi Matt,

    At which stage have you registered your plugin? It has to be Pre-operation if you want to update the same record which the plugin has triggered.

    Also the loop doesn't look right to me.  Shouldn't it be like this? 

    foreach (var x in _results)
    {
        _txttowrite =  _txttowrite + ", "+ x + ", ";
    }
    

    You can try debugging and see whether you get any results from your LINQ query. You can find how to debug a plugin here: http://msdn.microsoft.com/en-us/library/gg328574.aspx

    Thanks


    Sachith Chandrasiri

    Friday, July 11, 2014 6:21 AM
  • Hi,

    I registered it None for the isolation mode and database for location.

    For steps I have registered it against SetState and SetStateDynamicEntity for pre-operation.

    Have amended the _txttowrite line as well - thanks.

    regards,

    Matt


    • Edited by Matt_Hirst_UK Friday, July 11, 2014 8:53 AM updated response
    Friday, July 11, 2014 7:55 AM
  • Hi,

    Do the below changes to your code and then deploy it...

    1) Inherit the class from Iplugin

    2) Write your logic inside Execute Method instead of ExecutePreQuoteUpdate.

     public void Execute(IServiceProvider serviceProvider)
            {
    
                Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)
                serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));
    
                IOrganizationServiceFactory factory =
                (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
    // CRM Service Object
                IOrganizationService service = factory.CreateOrganizationService(context.UserId);
    
    // Your logic
    
    }

    Thanks and Regards,

    Gopinath.

    http://mscrmtechie.blogspot.com

     
    Friday, July 11, 2014 9:29 AM
  • Here is the entire code as it stands now:

    namespace Plugin_Project
    {
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using Microsoft.Xrm.Sdk;
        using System.ServiceModel;
        using System.Threading.Tasks;
        using Microsoft.Xrm.Sdk.Query;
    
    
        public class PreQuoteUpdate: Plugin
        {
    
            public void Execute(IServiceProvider serviceProvider)
            {
    
                Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)
                serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));
    
                IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                // CRM Service Object
                IOrganizationService service = factory.CreateOrganizationService(context.UserId);
    
                // Your logic
    
                Entity entity = null;
    
                // linq QUERY
                Quote currentQuote = entity.ToEntity<Quote>();
                using (GeneratedCode orgcontext = new GeneratedCode(service))
                {
                    var _results = (from quote in orgcontext.QuoteSet
                                    join qd in orgcontext.QuoteDetailSet on quote.QuoteId equals qd.QuoteId.Id
                                    join prod in orgcontext.ProductSet on qd.sp_SellingProductId.Id equals prod.ProductId
                                    where (quote.Name == "QUO-01694-D9H2")
                                    select prod.orb_ParentProductid).Distinct();
    
                    var _txttowrite = "";
                    foreach (var x in _results)
                    {
                        _txttowrite = _txttowrite + x + ", ";
                    }
    
                    currentQuote.ancon_quoteproducts = _txttowrite;
                }
    
            }
    
    
            public PreQuoteUpdate(): base(typeof(PreQuoteUpdate))
            {
                base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>(20, "Update", "quote", new Action<LocalPluginContext>(ExecutePreQuoteUpdate)));
                
            }
    
          
            protected void ExecutePreQuoteUpdate(LocalPluginContext localContext)
            {
                if (localContext == null)
                {
                    throw new ArgumentNullException("localContext");
                }
    
                IPluginExecutionContext context = localContext.PluginExecutionContext;
                IOrganizationService service = localContext.OrganizationService;
                ITracingService tracingService = localContext.TracingService;
                IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)localContext.ServiceProvider.GetService(typeof(IOrganizationServiceFactory));
    
    
               
            }
        }
    }

    It still does nothing, if I register it sandboxed and asynchronous and post-op I can see, by looking at the system jobs it fires but obviously the field is not updated.

    regards,

    Matt

    Friday, July 11, 2014 10:16 AM
  • Inherit your class from IPlugin not from Plugin.

    --

    Regards,

    Gopinath.

    Friday, July 11, 2014 10:58 AM
  • Gopinath,

    Thanks, can't believe I missed that.

    It now fires - excellent, but I receive the following error:

    Object reference not set to an instance of an object

    Any ideas?

    regards,

    Matt

    Friday, July 11, 2014 11:20 AM
  • Hi Matt,

    It is because you call the ToEntity method on this entity which is null.

     Entity entity = null;
    
                // linq QUERY
                Quote currentQuote = entity.ToEntity<Quote>();


    Sachith Chandrasiri

    Friday, July 11, 2014 11:38 AM
  • Hi Matt,

    I am glad, it helped you..

    Get the Entity object from Input Parameter..

        if (context.InputParameters.Contains("Target") &&
                   context.InputParameters["Target"] is Entity)
                {
                    Entity entity = (Entity)context.InputParameters["Target"];

    --

    Thanks and Regards,

    Gopinath

    Friday, July 11, 2014 11:42 AM
  • Entity entity = (Entity)context.InputParameters["Target"];
    
    if(entity.Attributes.Contains("statuscode"))
        entity.Attributes["statuscode"] = "";
    else

    entity.Attributes.add("statuscode", "");

    try this


    ms crm

    Friday, July 11, 2014 1:13 PM
  • Hi Matt

    Debugging plugins can be a nightmare

    I found doing the following eases the process:

    Create a string builder and populate it using several try-catch blocks where you expect there may be troublesome code.

    At the end, throw an error and pass it the stringbuilders text.

    Deploy it as a synchronous plugin, then fire it by updating/creating a record and you will see the error text, line by line.

    Pretty tedious, but it helps a lot. When its ready, remove the throw and set it back to async if needed

    Friday, July 11, 2014 3:36 PM
  • Hello Matt,

    I build the C# code, tested and it's working just fine. Take a look at how I did it:

    using System;
    using System.ServiceModel;
    using System.Linq;
    using Microsoft.Xrm.Sdk;
    using Microsoft.Xrm.Sdk.Query;
    
    namespace ClassLibrary1
    {
        public class QuoteProductsOnAField : IPlugin
        {
            public void Execute(IServiceProvider serviceProvider)
            {
                ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
                IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
    
                if (context.InputParameters.Contains("EntityMoniker") && context.InputParameters["EntityMoniker"] is EntityReference)
                {
                    EntityReference entity = (EntityReference)context.InputParameters["EntityMoniker"];
    
                    if (entity.LogicalName != "quote")
                        return;
    
                    IOrganizationServiceFactory serviceFactory =
                        (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                    IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
    
                    try
                    {
                        // Your Business Logic
    
                        using (ServiceContext svcContext = new ServiceContext(service))
                        {
                            var retrievedProducts = from p in svcContext.ProductSet
                                                    join qd in svcContext.QuoteDetailSet
                                                    on p.ProductId equals qd.ProductId.Id
                                                    where qd.QuoteId.Id == entity.Id
                                                    select new
                                                    {
                                                        product_name = p.Name
                                                    };
    
                            if (retrievedProducts != null)
                            {
                                var products = String.Empty;
    
                                foreach (var item in retrievedProducts)
                                {
                                    if (String.IsNullOrEmpty(products))
                                    {
                                        products = item.product_name;
                                    }
                                    else
                                    {
                                        products += ", " + item.product_name;
                                    }
                                }
    
                                Quote currentQuote = (Quote)service.Retrieve(Quote.EntityLogicalName, entity.Id, new ColumnSet(false));
    
                                currentQuote.new_Products = products;
    
                                service.Update(currentQuote);
                            }
                        }
                    }
    
                    catch (FaultException<OrganizationServiceFault> ex)
                    {
                        throw new InvalidPluginExecutionException("An error occurred in MyPlug-in.", ex);
                    }
    
                    catch (Exception ex)
                    {
                        tracingService.Trace("MyPlugin: {0}", ex.ToString());
                        throw;
                    }
                }
            }
        }
    }

    Register Steps for both "SetState" and "SetStateDynamicEntity" messages. Here is an example:


    Hope it helps,

    Elvis


    Saturday, July 12, 2014 4:55 PM
  • Hi Matt,

    If your requirement is fulfilled with the given answers, Please Mark the Question as Answered. So that it could help others.

    --

    Regards,

    Gopinath.

    Monday, July 14, 2014 8:37 AM
  • I have used this code example and double checked the registration of the plugin,my only difference is the eventhandler is "(Plugin) Plugin_Project.PreQuoteUpdate - Isolatable" there is an option to change this to "(Plugin) Plugin_Project.PreQuoteUpdate" but this then offers additional options for the "Eventing pipeline Stage of Execution".

    It does not update the field, multi-line textbox, I have added another new field, textbox, this doesn't get updated either.  There are no events placed in System jobs either.

    regards,

    Matt

    Monday, July 14, 2014 10:21 AM
  • I have edited the field to just output a text string, so can see the plugin fires and also that it writes to the field prior to activation, so I assume from this that the query returns no results just not sure why not.?

    Back to the drawing board on the query.

    regards,

    Matt

    Monday, July 14, 2014 10:42 AM
  • If I write to a textfield entity.LogicalName I can see "Quote" written to the field.

    If I write to a textfield entity.Id I see nothing written to the field - so I am assuming I am not getting the quote entity id and passing that to the query, hence no results.

    Any ideas why I am not returning the quote Id which I assume is the GUID?

    regards,

    Matt

    Monday, July 14, 2014 1:13 PM
  • Hi Matt,

    If possible, could you please paste the code. So that we can have look at it.

    --

    Regards,

    Gopinath.

    Monday, July 14, 2014 2:17 PM
  • Gopinath,

    I finally cracked it with all of your help on here - hopefully anyone else who may be struggling will see the steps I have gone through and it help them.

    The issue was the query was not working so always reporting nothing, no error just reporting nothing - so I went through the process of stripping the query just to pull a value from the the quote details and added the additional lines as needed and this worked.

    Thanks for all of your help.

    regards,

    Matt

    Monday, July 14, 2014 2:37 PM
  • One issue has occurred, we have products that are part of parent products and these parent products are top level so contain no parent products the following code then generates an error, how do I get it to ignore null values?

     using (GeneratedCode orgcontext = new GeneratedCode(service))
                        {
    
                            var retrievedProducts = (from p in orgcontext.ProductSet
                                                     join qd in orgcontext.QuoteDetailSet
                                                     on p.ProductId equals qd.sp_SellingProductId.Id
                                                     where qd.QuoteId.Id == entity.Id                                                 
                                                     select new
                                                     {
                                                         product_name = p.orb_ParentProductid.Name
                                                     }).Distinct();
    
    
                            var _txttowrite = string.Empty;
                            if (retrievedProducts != null)
                            {
                                // for each item returned write the output to a string.
    
                                foreach (var item in retrievedProducts)
                                {
                                    if (item.product_name != "")
                                    {
                                        if (String.IsNullOrEmpty(_txttowrite))
                                        {
                                            _txttowrite = item.product_name;
                                        }
                                        else
                                        {
                                            _txttowrite += ", " + item.product_name;
                                        }
                                    }
                                }
    
    
                            }

    regards,

    Matt

    Tuesday, August 12, 2014 10:17 AM