Ejemplo n.º 1
0
        /// <summary>
        /// Get instances of requested services topologicaly sorted by
        /// <see cref="DependsOnPluginAttribute"/>.
        /// </summary>
        /// <typeparam name="TService">Service type.</typeparam>
        /// <returns>A list of service instances.</returns>
        public static IEnumerable <TService> GetServices <TService>()
        {
            IEnumerable <Type> types = PluginAssembyLoader.GetTypes <TService>();

            types = types.TopologicalSort(x => x
                                          .GetCustomAttributes(typeof(DependsOnPluginAttribute), true)
                                          .Cast <DependsOnPluginAttribute>()
                                          .Select(z => z.GetType())
                                          .ExpandInterfaces());

            foreach (Type type in types)
            {
                ConstructorInfo ctorInfo =
                    type.GetConstructor(Type.EmptyTypes);

                if (ctorInfo == null)
                {
                    throw new ApplicationException(
                              $"Type \"{type.FullName}\" must have a parameterless constructor."
                              );
                }

                TService instance =
                    (TService)Activator.CreateInstance(type);

                yield return(instance);
            }
        }
Ejemplo n.º 2
0
        private static IEnumerable <string> GetAssemblyPathesForAllPlugins(
            string basePath,
            IEnumerable <string> whiteList = null)
        {
            // Return all the plugin folder names if white list is empty
            if (whiteList == null || whiteList.Count() == 0)
            {
                foreach (string pluginPath in
                         Directory.GetDirectories(basePath))
                {
                    foreach (string assemblyPath in PluginAssembyLoader.
                             GetAssemblyPathesForPlugin(pluginPath))
                    {
                        yield return(assemblyPath);
                    }
                }

                yield break;
            }

            List <PluginInfo> pluginInfos = new List <PluginInfo>();

            // If white list is presend then return the names of plugin folders
            // while respecting the white list
            List <string> list = whiteList.Select(s => s).ToList();

            foreach (string pluginPath in Directory.GetDirectories(basePath))
            {
                string dirName = Path.GetFileName(
                    pluginPath.RemoveTrailingSlash());

                pluginInfos.Add(new PluginInfo
                {
                    Name     = dirName,
                    BasePath = pluginPath
                });

                string listItem = list.FirstOrDefault(s => s.Equals(
                                                          dirName,
                                                          StringComparison.InvariantCultureIgnoreCase));

                if (!String.IsNullOrWhiteSpace(listItem))
                {
                    list.Remove(listItem);

                    foreach (string assemblyPath in PluginAssembyLoader
                             .GetAssemblyPathesForPlugin(pluginPath))
                    {
                        yield return(assemblyPath);
                    }
                }
            }

            PluginAssembyLoader.PluginInfos = pluginInfos.ToArray();
        }
        /// <summary>
        /// Adds services of each plugins to the
        /// <see cref="IApplicationBuilder"/> request execution pipeline.
        /// </summary>
        public static void UsePlugins(
            this IApplicationBuilder app)
        {
            IEnumerable <IConfigureAction> actions =
                PluginAssembyLoader.GetServices <IConfigureAction>();

            foreach (IConfigureAction action in actions)
            {
                action.Execute(app);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Get all the assemblies from white listed plugins
        /// including all subdirectories into current app domain.
        /// </summary>
        /// <param name="basePath">Base directory path for plugins.</param>
        /// <param name="whiteList">List of plugin names that should be loded,
        /// all other plugins will be ignored.</param>
        public static void LoadAssemblies(
            string basePath,
            ILoggerFactory loggerFactory,
            IEnumerable <string> whiteList = null)
        {
            PluginAssembyLoader._logger =
                loggerFactory.CreateLogger(typeof(PluginAssembyLoader));

            if (whiteList == null || whiteList.Count() == 0)
            {
                PluginAssembyLoader._logger.LogInformation(
                    $"Loading plugin assemblies from \"{basePath}\"");
            }
            else
            {
                PluginAssembyLoader._logger.LogInformation(
                    "Loading white listed plugin assemblies from \"{0}\"\n\t- {1}",
                    basePath,
                    String.Join("\n\t- ", whiteList));
            }

            // Get all the pathes recursevly respecting whitelist
            string[] assemblyPathes = PluginAssembyLoader
                                      .GetAssemblyPathesForAllPlugins(basePath, whiteList)
                                      .ToArray();

            PluginAssembyLoader._logger
            .LogDebug($"Found {assemblyPathes.Count()} plugin assemblies");

            // Load all the assemblies
            PluginAssembyLoader.LoadAssemblies(assemblyPathes);

            PluginAssembyLoader._logger
            .LogDebug($"Loading plugin assemblies completed");

            AssemblyLoadContext.Default.Resolving += (loadContext, name) =>
            {
                PluginAssembyLoader._logger.LogDebug(
                    $"Try to resolve \"{name.FullName}\"");

                return(null);
            };
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Get all the assembly (*.dll) pathes from the plugin directory
        /// including all subdirectories.
        /// </summary>
        /// <param name="pluginPath">Base path of the plugin directory.</param>
        /// <returns>A list of assembly pathes.</returns>
        private static IEnumerable <string> GetAssemblyPathesForPlugin(
            string pluginPath)
        {
            foreach (string assemblyPath in
                     Directory.EnumerateFiles(pluginPath, "*.dll"))
            {
                yield return(assemblyPath);
            }

            foreach (string subDirPath in
                     Directory.GetDirectories(pluginPath))
            {
                foreach (var subAssemblyPath in PluginAssembyLoader
                         .GetAssemblyPathesForPlugin(subDirPath))
                {
                    yield return(subAssemblyPath);
                }
            }
        }
Ejemplo n.º 6
0
        public static void AddPlugins(
            this IServiceCollection serviceCollection)
        {
            IServiceProvider serviceProvider =
                serviceCollection.BuildServiceProvider();

            ILogger logger = serviceProvider
                             .GetService <ILoggerFactory>()
                             .CreateLogger(typeof(IServiceCollectionExtensions));

            IEnumerable <IConfigureServicesAction> actions =
                PluginAssembyLoader.GetServices <IConfigureServicesAction>();

            foreach (IConfigureServicesAction action in actions)
            {
                logger.LogInformation(
                    "Executing ConfigureServices action \"{0}\"",
                    action.GetType().FullName);

                action.Execute(serviceCollection);
            }
        }
        /// <summary>
        /// Adds MVC to the <see cref="IApplicationBuilder"/> request
        /// execution pipeline, configured to work with plugin architecture.
        /// </summary>
        /// <param name="app">
        /// Instance of <see cref="IApplicationBuilder"/>.
        /// </param>
        public static void UsePluginsMvc(
            this IApplicationBuilder app)
        {
            ILogger logger = app.ApplicationServices
                             .GetService <ILoggerFactory>().CreateLogger("Plugins");

            app.UseMvc(routeBuilder =>
            {
                foreach (IUseMvcAction action in PluginAssembyLoader
                         .GetServices <IUseMvcAction>())
                {
                    logger.LogInformation(
                        "Executing UseMvc action '{0}'",
                        action.GetType().FullName);

                    action.Execute(routeBuilder);
                }

                routeBuilder.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
        public static void AddPluginsMvc(
            this IServiceCollection services,
            IViewLocationExpander viewLocationExpander = null)
        {
            ServiceProvider serviceProvider = services.BuildServiceProvider();

            ILogger logger = serviceProvider
                             .GetService <ILoggerFactory>()
                             .CreateLogger(typeof(IServiceCollectionExtensions));

            // Dont use uglycase urls !
            services.AddRouting((options) =>
            {
                options.LowercaseUrls = true;
            });

            IMvcBuilder mvcBuilder = services
                                     .AddMvc()
                                     .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
                                     .AddViewLocalization()
                                     .AddDataAnnotationsLocalization()
                                     .ConfigureApplicationPartManager(manager =>
            {
                IApplicationFeatureProvider toRemove = manager
                                                       .FeatureProviders
                                                       .First(f => f is MetadataReferenceFeatureProvider);

                manager.FeatureProviders
                .Remove(toRemove);

                manager.FeatureProviders
                .Add(new ReferencesMetadataReferenceFeatureProvider());
            });

            IEnumerable <Assembly> assemblies = PluginAssembyLoader.Assemblies;

            foreach (Assembly assembly in assemblies)
            {
                logger.LogDebug(
                    "Adding mvc application part: \"{0}\"",
                    assembly.FullName
                    );

                mvcBuilder.AddApplicationPart(assembly);
            }

            mvcBuilder.AddRazorOptions(razor =>
            {
                if (viewLocationExpander != null)
                {
                    logger.LogDebug(
                        "Replacing default view location expander with: \"{0}\"",
                        viewLocationExpander.GetType().FullName
                        );

                    razor.ViewLocationExpanders.Clear();
                    razor.ViewLocationExpanders.Add(viewLocationExpander);
                }
            });

            IEnumerable <IAddMvcAction> actions = PluginAssembyLoader
                                                  .GetServices <IAddMvcAction>();

            foreach (IAddMvcAction action in actions)
            {
                logger.LogDebug(
                    "Executing add mvc action \"{0}\"",
                    action.GetType().FullName
                    );

                action.Execute(mvcBuilder);
            }
        }