public static void SetupAssemblyPlugins(
            this CrmPluginAssembly pluginAssembly,
            Assembly assembly,
            IReadOnlyCollection <XElement> unsecureConfigItems,
            IEnumerable <SdkMessage> messages,
            IEnumerable <SdkMessageFilter> messageFilters)
        {
            Version sdkVersion = null;
            var     types      =
                assembly
                .GetExportedTypes()
                .Where(
                    t =>
                    !t.IsAbstract &&
                    t.IsClass &&
                    (t.Name.EndsWith("Plugin") || t.Name.EndsWith("Activity")));

            foreach (var t in types)
            {
                CrmPluginType       type;
                CrmPluginIsolatable isolatable;

                var xrmPlugin = t.GetInterface(typeof(IPlugin).FullName);
                if (xrmPlugin != null)
                {
                    type       = CrmPluginType.Plugin;
                    isolatable = CrmPluginIsolatable.Yes;
                    if (sdkVersion == null)
                    {
                        sdkVersion = xrmPlugin.Assembly.GetName().Version;
                        pluginAssembly.SdkVersion = new Version(xrmPlugin.Assembly.GetName().Version.Major, xrmPlugin.Assembly.GetName().Version.Minor);
                    }

                    pluginAssembly.SdkVersion = new Version(sdkVersion.Major, sdkVersion.Minor);
                }
                else if (t.IsSubclassOf(typeof(Activity)))
                {
                    type       = CrmPluginType.WorkflowActivity;
                    isolatable = CrmPluginIsolatable.No;
                }
                else
                {
                    throw new Exception("Class is not plugin or workflow");
                }

                var plugin =
                    new CrmPlugin
                {
                    TypeName     = t.FullName,
                    PluginType   = type,
                    AssemblyId   = pluginAssembly.AssemblyId,
                    AssemblyName = pluginAssembly.Name,
                    Isolatable   = isolatable,
                    FriendlyName = Guid.NewGuid().ToString()
                };

                if (type == CrmPluginType.WorkflowActivity)
                {
                    var attr = t.GetCustomAttribute <WorkflowActivityAttribute>();
                    plugin.WorkflowActivityGroupName = " " + attr.WorkflowActivityGroupName;
                    plugin.Name = " " + attr.Name;
                }

                var pluginEntityType = t.BaseType?.GetGenericArguments().LastOrDefault();
                if (pluginEntityType == null)
                {
                    // note: be sure - it is workflow:)
                    pluginAssembly.AddPlugin(plugin);
                    continue;
                }

                var splitted = t.FullName?.Split('.').Reverse().Take(2).ToArray();
                var typeName = splitted?[0].Replace("Plugin", string.Empty);
                plugin.Name = $" {splitted?[1]}: {typeName}";

                var stepMethods = t.GetMethods(BindingFlags.Public | BindingFlags.Instance).Where(m => m.DeclaringType == t).ToArray();
                foreach (var stepMethod in stepMethods)
                {
                    var pluginStepAttrs     = stepMethod.GetCustomAttributes <PluginStepAttribute>();
                    var filteringAttributes = stepMethod.GetCustomAttribute <FilteringAttributesAttribute>();
                    foreach (var pluginStepAttr in pluginStepAttrs)
                    {
                        var step =
                            new CrmPluginStep
                        {
                            AssemblyId = plugin.AssemblyId,
                            PluginId   = plugin.Id,
                            DeleteAsyncOperationIfSuccessful = pluginStepAttr.DeleteAsyncOperationIfSuccessful,
                            Deployment = CrmPluginStepDeployment.ServerOnly,
                            Enabled    = pluginStepAttr.Enabled,
                            Name       = RegistrationHelper.GenerateStepName(typeName, pluginStepAttr.PluginMessageName, pluginStepAttr.EntityLogicalName.ToLowerInvariant(), null),
                            Rank       = pluginStepAttr.Rank,
                            Stage      = (CrmPluginStepStage)pluginStepAttr.Stage,
                            Mode       = pluginStepAttr.ExecutionMode == PluginExecutionMode.Asynchronous ? CrmPluginStepMode.Asynchronous : CrmPluginStepMode.Synchronous,
                            MessageId  = messages.First(m => m.Name == pluginStepAttr.PluginMessageName).Id
                        };
                        var filter =
                            messageFilters.FirstOrDefault(
                                f =>
                                f.SdkMessageId.Id == step.MessageId &&
                                f.PrimaryEntityLogicalName == pluginStepAttr.EntityLogicalName.ToLowerInvariant());
                        if (filter == null)
                        {
                            throw new Exception($"{pluginStepAttr.EntityLogicalName} entity doesn't registered yet");
                        }

                        step.MessageEntityId = filter.Id;
                        if (filteringAttributes != null)
                        {
                            step.FilteringAttributes = filteringAttributes.ToString();
                        }

                        var unsecureItem = unsecureConfigItems.FirstOrDefault(it => it.Attribute("key").Value == pluginStepAttr.UnsecureConfig);
                        if (unsecureItem != null)
                        {
                            var value = unsecureItem.Attribute("value").Value;
                            step.UnsecureConfiguration = value == $"#{{{pluginStepAttr.UnsecureConfig}}}" ? unsecureItem.Attribute("default").Value : value;
                        }

                        foreach (var p in stepMethod.GetParameters().Where(p => p.ParameterType == pluginEntityType))
                        {
                            var imageParameters = p.GetCustomAttribute <ImageParametersAttribute>();
                            if (imageParameters == null)
                            {
                                continue;
                            }

                            CrmPluginImage image;
                            switch (p.Name)
                            {
                            case "preEntityImage":
                                image = CreateImage(step, imageParameters.ToString(), pluginStepAttr.PluginMessageName, CrmPluginImageType.PreImage);
                                step.AddImage(image);
                                break;

                            case "postEntityImage":
                                image = CreateImage(step, imageParameters.ToString(), pluginStepAttr.PluginMessageName, CrmPluginImageType.PostImage);
                                step.AddImage(image);
                                break;
                            }
                        }

                        plugin.AddStep(step);
                    }
                }

                pluginAssembly.AddPlugin(plugin);
            }
        }
        public static void SetupAssemblyPlugins(
            this CrmPluginAssembly pluginAssembly,
            Version sdkVersion,
            XDocument config,
            IEnumerable <SdkMessage> messages,
            IEnumerable <SdkMessageFilter> messageFilters)
        {
            XNamespace ns             = "http://schemas.microsoft.com/crm/2011/tools/pluginregistration";
            var        pluginElements = config.Root.Element(ns + "Solutions").Element(ns + "Solution").Element(ns + "PluginTypes").Elements(ns + "Plugin");

            foreach (var pluginElement in pluginElements)
            {
                CrmPluginType       type;
                CrmPluginIsolatable isolatable;

                var typeName = pluginElement.Attribute("TypeName").Value;
                if (typeName.EndsWith("Plugin"))
                {
                    type       = CrmPluginType.Plugin;
                    isolatable = CrmPluginIsolatable.Yes;
                    if (sdkVersion != null)
                    {
                        pluginAssembly.SdkVersion = new Version(sdkVersion.Major, sdkVersion.Minor);
                    }
                }
                else if (typeName.EndsWith("Activity"))
                {
                    type       = CrmPluginType.WorkflowActivity;
                    isolatable = CrmPluginIsolatable.No;
                }
                else
                {
                    throw new Exception("Class is not plugin or workflow");
                }

                var plugin =
                    new CrmPlugin
                {
                    TypeName     = typeName,
                    PluginType   = type,
                    AssemblyId   = pluginAssembly.AssemblyId,
                    AssemblyName = pluginAssembly.Name,
                    Isolatable   = isolatable,
                    FriendlyName = pluginElement.Attribute("FriendlyName").Value
                };

                if (type == CrmPluginType.WorkflowActivity)
                {
                    plugin.WorkflowActivityGroupName = " " + pluginElement.Attribute("FriendlyName").Value;
                    plugin.Name = " " + pluginElement.Attribute("Name").Value;
                    pluginAssembly.AddPlugin(plugin);
                    continue;
                }

                var splitted   = typeName.Split('.').Reverse().Take(2).ToArray();
                var pluginName = splitted[0].Replace("Plugin", string.Empty);
                plugin.Name = $" {splitted[1]}: {pluginName}";

                foreach (var pluginStepEl in pluginElement.Element(ns + "Steps").Elements(ns + "Step"))
                {
                    var step =
                        new CrmPluginStep
                    {
                        AssemblyId = plugin.AssemblyId,
                        PluginId   = plugin.Id,
                        DeleteAsyncOperationIfSuccessful = false, // ToDo: implement for ugly config
                        Deployment  = CrmPluginStepDeployment.ServerOnly,
                        Enabled     = true,                       // ToDo: implement for ugly config
                        Name        = pluginStepEl.Attribute("Name").Value,
                        Rank        = int.Parse(pluginStepEl.Attribute("Rank").Value),
                        Stage       = pluginStepEl.Attribute("Stage").Value == "PreInsideTransaction" ? CrmPluginStepStage.PreOperation : CrmPluginStepStage.PostOperation,   // ToDo: CrmPluginStepStage.PreValidation
                        Mode        = pluginStepEl.Attribute("Mode").Value == PluginExecutionMode.Asynchronous.ToString().ToLowerInvariant() ? CrmPluginStepMode.Asynchronous : CrmPluginStepMode.Synchronous,
                        MessageId   = messages.First(m => m.Name == pluginStepEl.Attribute("MessageName").Value).Id,
                        Description = pluginStepEl.Attribute("Description").Value
                    };
                    var filter =
                        messageFilters.FirstOrDefault(
                            f =>
                            f.SdkMessageId.Id == step.MessageId &&
                            f.PrimaryEntityLogicalName == pluginStepEl.Attribute("PrimaryEntityName").Value.ToLowerInvariant());
                    if (filter == null)
                    {
                        throw new Exception($"{pluginStepEl.Attribute("PrimaryEntityName").Value} entity doesn't registered yet");
                    }

                    step.MessageEntityId = filter.Id;
                    var attr = pluginStepEl.Attribute("FilteringAttributes");
                    if (!string.IsNullOrEmpty(attr?.Value))
                    {
                        step.FilteringAttributes = attr.Value;
                    }

                    var unsecureItem = pluginStepEl.Attribute("CustomConfiguration").Value;
                    if (!string.IsNullOrEmpty(unsecureItem))
                    {
                        step.UnsecureConfiguration = unsecureItem;
                    }

                    foreach (var imageEl in pluginStepEl.Element(ns + "Images").Elements(ns + "Image"))
                    {
                        var image = CreateImage(step, imageEl, pluginStepEl);
                        if (image != null)
                        {
                            step.AddImage(image);
                        }
                    }

                    plugin.AddStep(step);
                }

                pluginAssembly.AddPlugin(plugin);
            }
        }