public void Execute(IServiceProvider serviceProvider)
        {
            var context        = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            var userId         = context.UserId;
            var message        = context.MessageName;
            var stage          = context.Stage;
            var isAsync        = context.Mode == 1;

            var type = (CrmEventType)Enum.Parse(typeof(CrmEventType), context.MessageName);

            IPluginContext pluginContext = new Services.PluginContext(this.UnsecureConfig, this.SecureConfig, context, type, userId);

            using (var serviceCache = new Reflection.ServiceCache(context, serviceFactory, tracingService, pluginContext))
            {
                var entityName = context.PrimaryEntityName;

                if (Reflection.Types.MESSAGE_WITHOUT_PRIMARY_ENTITY.Contains(message))
                {
                    entityName = null;
                }

                var methods = PluginMethodCache.ForPlugin(this.GetType(), stage, message, entityName, context.Mode == 1);

                foreach (var method in methods)
                {
                    #region find out if method is relevant, looking a target fields
                    if (message == Attributes.StepAttribute.MessageEnum.Update.ToString() && !method.FilterAllProperties)
                    {
                        var targetEntity = (Microsoft.Xrm.Sdk.Entity)context.InputParameters["Target"];
                        if (!method.IsRelevant(targetEntity))
                        {
                            continue;
                        }
                    }
                    #endregion

                    #region now resolve all parameters
                    var args = new object[method.Parameters.Length];
                    var ix   = 0;
                    System.ComponentModel.INotifyPropertyChanged mergedimage = null;
                    System.ComponentModel.INotifyPropertyChanged target      = null;
                    foreach (var p in method.Parameters)
                    {
                        args[ix] = serviceCache.Resolve(p);

                        if (stage <= 20)
                        {
                            if (p.IsMergedimage)
                            {
                                mergedimage = (System.ComponentModel.INotifyPropertyChanged)args[ix];
                            }

                            if (p.IsTarget)
                            {
                                target = args[ix] as System.ComponentModel.INotifyPropertyChanged;
                            }
                        }
                        ix++;
                    }
                    #endregion

                    #region add mergedimage eventlistener if applicable
                    PropertyMirror mergedimageMirror = null;
                    PropertyMirror targetMirror      = null;

                    if (stage <= 20)
                    {
                        if (mergedimage != null)
                        {
                            var tg = (Microsoft.Xrm.Sdk.Entity)context.InputParameters["Target"];
                            mergedimageMirror            = new PropertyMirror(tg);
                            mergedimage.PropertyChanged += mergedimageMirror.MirrorpropertyChanged;
                        }

                        if (mergedimage != null && target != null)
                        {
                            targetMirror            = new PropertyMirror((Microsoft.Xrm.Sdk.Entity)mergedimage);
                            target.PropertyChanged += targetMirror.MirrorpropertyChanged;
                        }
                    }
                    #endregion

                    #region run the method
                    try
                    {
                        method.Invoke(this, args);
                    } finally
                    {
                        #region cleanup mirror
                        if (stage <= 20)
                        {
                            if (mergedimageMirror != null)
                            {
                                mergedimage.PropertyChanged -= mergedimageMirror.MirrorpropertyChanged;
                                mergedimageMirror            = null;
                            }

                            if (targetMirror != null)
                            {
                                target.PropertyChanged -= targetMirror.MirrorpropertyChanged;
                                targetMirror            = null;
                            }
                        }
                        #endregion

                        #region prepare for next method
                        serviceCache.OnStepFinalize();
                        #endregion
                    }
                    #endregion
                }
            }
        }
Example #2
0
        public void Execute(IServiceProvider serviceProvider)
        {
            var context        = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

            var toolOrgService = serviceFactory.CreateOrganizationService(null);

            var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            var userId         = context.UserId;
            var message        = context.MessageName;
            var stage          = context.Stage;
            var isAsync        = context.Mode == 1;

            var type = message.Contains("_") ? CrmEventType.CustomPlugin : (CrmEventType)Enum.Parse(typeof(CrmEventType), context.MessageName);

            IPluginContext pluginContext = new Services.PluginContext(this.UnsecureConfig, this.SecureConfig, context, type, userId);

            using (var serviceCache = new Reflection.ServiceCache(context, serviceFactory, tracingService, pluginContext, this.UnsecureConfig, this.SecureConfig))
            {
                var entityName = context.PrimaryEntityName;

                if (entityName == "none" || Reflection.Types.MESSAGE_WITHOUT_PRIMARY_ENTITY.Contains(message))
                {
                    entityName = null;
                }

                var methods = PluginMethodCache.ForPlugin(this.GetType(), stage, message, entityName, context.Mode == 1);

                var logs = new System.Collections.Generic.List <string>();
                try
                {
                    foreach (var method in methods)
                    {
                        #region evaluate if needed - based on If attributes
                        if (method.IfAttribute != null)
                        {
                            var con = Reflection.MethodConditionEvaluater.Evaluate(method.IfAttribute, context);
                            if (!con)
                            {
                                continue;
                            }
                        }
                        #endregion

                        var nextlog = $"{method.Name}(";
                        #region find out if method is relevant, looking a target fields
                        if (message == Attributes.StepAttribute.MessageEnum.Update.ToString() && !method.FilterAllProperties)
                        {
                            var targetEntity = (Microsoft.Xrm.Sdk.Entity)context.InputParameters["Target"];
                            if (!method.IsRelevant(targetEntity))
                            {
                                continue;
                            }
                        }
                        #endregion

                        #region now resolve all parameters
                        var args = new object[method.Parameters.Length];
                        var ix   = 0;
                        System.ComponentModel.INotifyPropertyChanged mergedimage = null;
                        System.ComponentModel.INotifyPropertyChanged target      = null;
                        var comma = "";
                        foreach (var p in method.Parameters)
                        {
                            nextlog += $"{comma}{p?.FromType?.FullName}";
                            comma    = ", ";
                            if (p.IsInputParameter)
                            {
                                if (context.InputParameters.ContainsKey(p.Name))
                                {
                                    args[ix] = context.InputParameters[p.Name];
                                }
                                else
                                {
                                    if (p.Name != null)
                                    {
                                        if (p.Name.ToLower() == nameof(this.UnsecureConfig).ToLower())
                                        {
                                            args[ix] = this.UnsecureConfig;
                                        }
                                        else
                                        if (p.Name.ToLower() == nameof(this.SecureConfig).ToLower())
                                        {
                                            args[ix] = this.SecureConfig;
                                        }
                                        else
                                        {
                                            args[ix] = null;
                                        }
                                    }
                                    else
                                    {
                                        args[ix] = null;
                                    }
                                }
                            }
                            else
                            {
                                args[ix] = serviceCache.Resolve(p, toolOrgService);
                            }

                            #region set TargetAttributes
                            if (message == "Create" || message == "Update")
                            {
                                if (p.IsMergedimage || p.IsPreimage || p.IsPostimage)
                                {
                                    var tap = args[ix].GetType().GetProperty("TargetAttributes");

                                    if (tap != null)
                                    {
                                        var tg = (Microsoft.Xrm.Sdk.Entity)context.InputParameters["Target"];
                                        tap.SetValue(args[ix], tg.Attributes);
                                    }
                                }
                            }
                            #endregion

                            #region set preimage attributes
                            if (p.IsMergedimage || p.IsTarget || p.IsPreimage || p.IsPostimage)
                            {
                                if (message == "Update" || message == "Delete")
                                {
                                    if (context.PreEntityImages != null && context.PreEntityImages.Values != null)
                                    {
                                        var col = new AttributeCollection();
                                        foreach (Entity pre in context.PreEntityImages.Values)
                                        {
                                            foreach (var at in pre.Attributes)
                                            {
                                                if (!col.Keys.Contains(at.Key))
                                                {
                                                    col.Add(at.Key, at.Value);
                                                }
                                            }
                                        }
                                        var tap = args[ix].GetType().GetProperty("PreimageAttributes");

                                        if (tap != null)
                                        {
                                            tap.SetValue(args[ix], col);
                                        }
                                    }
                                }
                            }
                            #endregion

                            #region add property notification to ensure mirror of set in pre state on merged images
                            if (stage <= 20 && message == "Update")
                            {
                                if (p.IsMergedimage)
                                {
                                    mergedimage = (System.ComponentModel.INotifyPropertyChanged)args[ix];
                                }

                                if (p.IsTarget)
                                {
                                    target = args[ix] as System.ComponentModel.INotifyPropertyChanged;
                                }
                            }
                            #endregion
                            ix++;
                        }
                        #endregion

                        #region add mergedimage eventlistener if applicable
                        PropertyMirror mergedimageMirror = null;
                        PropertyMirror targetMirror      = null;

                        if (stage <= 20 && message == "Update")
                        {
                            if (mergedimage != null)
                            {
                                var tg = (Microsoft.Xrm.Sdk.Entity)context.InputParameters["Target"];
                                mergedimageMirror            = new PropertyMirror(tg);
                                mergedimage.PropertyChanged += mergedimageMirror.MirrorpropertyChanged;
                            }

                            if (mergedimage != null && target != null)
                            {
                                targetMirror            = new PropertyMirror((Microsoft.Xrm.Sdk.Entity)mergedimage);
                                target.PropertyChanged += targetMirror.MirrorpropertyChanged;
                            }
                        }
                        #endregion

                        #region run the method
                        var inError = false;
                        nextlog += ")";
                        try
                        {
                            logs.Add($"before: {nextlog}");
                            var result = method.Invoke(this, args);
                            logs.Add($"after: {nextlog}");

                            if (result != null && method.OutputProperties != null && method.OutputProperties.Count > 0)
                            {
                                foreach (var key in method.OutputProperties.Keys)
                                {
                                    var output = method.OutputProperties[key];
                                    var value  = key.GetValue(result);
                                    if (value != null)
                                    {
                                        #region map strongly typed entities back to base entities to allow correct serrialization back to client
                                        if (value is Microsoft.Xrm.Sdk.Entity e && value.GetType() != typeof(Microsoft.Xrm.Sdk.Entity))
                                        {
                                            var entity = new Microsoft.Xrm.Sdk.Entity(e.LogicalName, e.Id);
                                            entity.Attributes = e.Attributes;
                                            value             = entity;
                                        }

                                        if (value is Microsoft.Xrm.Sdk.EntityCollection ec && ec.Entities != null && ec.Entities.Count > 0)
                                        {
                                            var final = new Microsoft.Xrm.Sdk.EntityCollection {
                                                EntityName = ec.EntityName
                                            };
                                            foreach (var ent in ec.Entities)
                                            {
                                                if (ent.GetType() == typeof(Microsoft.Xrm.Sdk.Entity))
                                                {
                                                    final.Entities.Add(ent);
                                                }
                                                else
                                                {
                                                    var entity = new Microsoft.Xrm.Sdk.Entity(ent.LogicalName, ent.Id);
                                                    entity.Attributes = ent.Attributes;
                                                    final.Entities.Add(entity);
                                                }
                                            }
                                            value = final;
                                        }
                                        #endregion

                                        context.OutputParameters[output.LogicalName] = value;
                                    }
                                }
                            }
                        }
                        catch (Microsoft.Xrm.Sdk.InvalidPluginExecutionException)
                        {
                            inError = true;
                            throw;
                        }
                        catch (System.Reflection.TargetInvocationException te)
                        {
                            inError = true;
                            if (te.InnerException != null && te.InnerException is Microsoft.Xrm.Sdk.InvalidPluginExecutionException)
                            {
                                throw te.InnerException;
                            }

                            if (te.InnerException != null)
                            {
                                throw new InvalidPluginExecutionException(te.InnerException.Message, te.InnerException);
                            }

                            throw new InvalidPluginExecutionException(te.Message, te);
                        }
                        catch (Exception be)
                        {
                            inError = true;
                            if (be.GetType().BaseType?.FullName == "Kipon.Xrm.Exceptions.BaseException")
                            {
                                // it is not a unit test, its the real thing, so we map the exception to a supported exception to allow message to parse all the way to the client
                                throw new InvalidPluginExecutionException($"{be.GetType().FullName}: {be.Message}", be);
                            }

                            throw new InvalidPluginExecutionException(be.Message, be);
                        }
                        finally
                        {
                            if (!inError)
                            {
                                #region cleanup mirror
                                if (stage <= 20)
                                {
                                    if (mergedimageMirror != null)
                                    {
                                        mergedimage.PropertyChanged -= mergedimageMirror.MirrorpropertyChanged;
                                        mergedimageMirror            = null;
                                    }

                                    if (targetMirror != null)
                                    {
                                        target.PropertyChanged -= targetMirror.MirrorpropertyChanged;
                                        targetMirror            = null;
                                    }
                                }
                                #endregion

                                #region prepare for next method
                                serviceCache.OnStepFinalize();
                                #endregion
                            }
                        }
                        #endregion
                    }
                } catch (Exception ex)
                {
                    tracingService.Trace(ex.Message);
                    tracingService.Trace(ex.GetType().FullName);
                    tracingService.Trace(ex.StackTrace);
                    foreach (var l in logs)
                    {
                        tracingService.Trace(l);
                    }
                    throw;
                }
            }
        }
        public void Execute(IServiceProvider serviceProvider)
        {
            var context        = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

            var userId  = context.UserId;
            var message = context.MessageName;

            if (message != "Retrieve" && message != "RetrieveMultiple")
            {
                throw new InvalidPluginExecutionException($"Unsupported message in VirtualEntityPlugin { message }. Only Retrieve and RetrieveMultiple is supported");
            }

            var type = (CrmEventType)Enum.Parse(typeof(CrmEventType), context.MessageName);

            IPluginContext pluginContext = new Services.PluginContext(this.UnsecureConfig, this.SecureConfig, context, type, userId);

            IOrganizationService toolOrgService = null;


            if (type == CrmEventType.Retrieve || type == CrmEventType.RetrieveMultiple)
            {
                toolOrgService = serviceFactory.CreateOrganizationService(null);
            }

            using (var serviceCache = new Reflection.ServiceCache(context, serviceFactory, tracingService, pluginContext, this.UnsecureConfig, this.SecureConfig))
            {
                var method = PluginMethodCache.ForPlugin(this.GetType(), 30, message, context.PrimaryEntityName, context.Mode == 1).Single();

                var args = new object[method.Parameters.Length];

                var ix = 0;

                Microsoft.Xrm.Sdk.Entity datasource = null;

                foreach (var p in method.Parameters)
                {
                    if (p.Name != null && p.Name.ToLower() == "datasource")
                    {
                        if (datasource == null)
                        {
                            throw new NotImplementedException();
                        }
                        args[ix] = datasource;
                    }
                    else
                    {
                        args[ix] = serviceCache.Resolve(p, toolOrgService);
                    }
                    ix++;
                }

                var result = method.Invoke(this, args);
                if (result != null)
                {
                    if (message == "Retrieve")
                    {
                        var be = result as Microsoft.Xrm.Sdk.Entity;
                        if (be == null)
                        {
                            throw new InvalidPluginExecutionException("Return from virtual antity Retrieve must be of type Microsoft.Xrm.Sdk.Entity");
                        }

                        if (be.GetType() != typeof(Microsoft.Xrm.Sdk.Entity))
                        {
                            var fr = new Microsoft.Xrm.Sdk.Entity {
                                Id = be.Id, LogicalName = be.LogicalName
                            };
                            fr.Attributes = be.Attributes;
                            be            = fr;
                        }

                        this.RemoveNullValues(be);
                        context.OutputParameters["BusinessEntity"] = be;
                    }

                    if (message == "RetrieveMultiple")
                    {
                        var bes = result as Microsoft.Xrm.Sdk.EntityCollection;
                        if (bes == null)
                        {
                            throw new InvalidPluginExecutionException("Return from virtual entity RetrieveMultiple must be of type Microsoft.Xrm.Sdk.EntityCollection");
                        }

                        var entities = bes.Entities.ToArray();
                        bes.Entities.Clear();


                        foreach (var be in entities)
                        {
                            if (be.GetType() == typeof(Microsoft.Xrm.Sdk.Entity))
                            {
                                bes.Entities.Add(be);
                            }
                            else
                            {
                                var fr = new Microsoft.Xrm.Sdk.Entity {
                                    Id = be.Id, LogicalName = be.LogicalName
                                };
                                fr.Attributes = be.Attributes;
                                bes.Entities.Add(fr);
                            }
                        }

                        foreach (var fe in bes.Entities)
                        {
                            this.RemoveNullValues(fe);
                        }
                        context.OutputParameters["BusinessEntityCollection"] = bes;
                    }
                }
            }
        }