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