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);
            }
        }