private void HandleCustomAction(IPluginExecutionContext context, PersistentTracingService tracing, IOrganizationService service)
        {
            var config = ProcessorConfig.Parse(context.InputParameters["jsonInput"] as string);

            if (config.Target == null)
            {
                throw new InvalidPluginExecutionException("Target property inside JSON parameters is needed for custom actions");
            }

            ColumnSet columnSet;

            if (config.TargetColumns != null)
            {
                columnSet = new ColumnSet(config.TargetColumns);
            }
            else
            {
                columnSet = new ColumnSet(true);
            }

            try
            {
                var dataSource = service.Retrieve(config.Target.LogicalName, config.Target.Id, columnSet);

                if (!CheckExecutionCriteria(config, dataSource, service, tracing))
                {
                    tracing.Trace("Execution criteria not met, aborting");

                    var abortResult = new ProcessingResult
                    {
                        Success  = true,
                        Result   = config.Template,
                        TraceLog = tracing.TraceLog
                    };
                    context.OutputParameters["jsonOutput"] = SerializeResult(abortResult);

                    return;
                }

                var output = ProcessTemplate(tracing, service, dataSource, config.Template);

                var result = new ProcessingResult
                {
                    Success  = true,
                    Result   = output,
                    TraceLog = tracing.TraceLog
                };
                context.OutputParameters["jsonOutput"] = SerializeResult(result);
            }
            catch (Exception ex)
            {
                var result = new ProcessingResult
                {
                    Success  = false,
                    Error    = ex.Message,
                    TraceLog = tracing.TraceLog
                };
                context.OutputParameters["jsonOutput"] = SerializeResult(result);
            }
        }
        private void HandleCustomAction(IPluginExecutionContext context, PersistentTracingService tracing, IOrganizationService service)
        {
            var config = ProcessorConfig.Parse(context.InputParameters["jsonInput"] as string);

            if (config.Target == null && config.TargetEntity == null)
            {
                throw new InvalidPluginExecutionException("Target property inside JSON parameters is needed for custom actions");
            }

            ColumnSet columnSet;

            if (config.TargetColumns != null)
            {
                columnSet = new ColumnSet(config.TargetColumns);
            }
            else
            {
                columnSet = new ColumnSet(true);
            }

            try
            {
                var dataSource = config.TargetEntity != null ? config.TargetEntity : service.Retrieve(config.Target.LogicalName, config.Target.Id, columnSet);

                if (!CheckExecutionCriteria(config, dataSource, service, tracing))
                {
                    tracing.Trace("Execution criteria not met, aborting");

                    var abortResult = new ProcessingResult
                    {
                        Success  = true,
                        Result   = config.Template,
                        TraceLog = tracing.TraceLog
                    };
                    context.OutputParameters["jsonOutput"] = SerializeResult(abortResult);

                    return;
                }

                var templateText = RetrieveTemplate(config.Template, config.TemplateField, dataSource, service, tracing);

                if (string.IsNullOrEmpty(templateText))
                {
                    tracing.Trace("Template is empty, aborting");
                    return;
                }

                var output = TokenMatcher.ProcessTokens(templateText, dataSource, new OrganizationConfig {
                    OrganizationUrl = config.OrganizationUrl
                }, service, tracing);

                var result = new ProcessingResult
                {
                    Success  = true,
                    Result   = output,
                    TraceLog = tracing.TraceLog
                };
                context.OutputParameters["jsonOutput"] = SerializeResult(result);

                TriggerUpdateConditionally(output, dataSource, config, service);
            }
            catch (Exception ex)
            {
                var result = new ProcessingResult
                {
                    Success  = false,
                    Error    = ex.Message,
                    TraceLog = tracing.TraceLog
                };
                context.OutputParameters["jsonOutput"] = SerializeResult(result);

                if (config.ThrowOnCustomActionError)
                {
                    throw;
                }
            }
        }