From e6cda35a46e7470aa97d7b9c1fae3cd4d5d1f76b Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 29 Oct 2019 21:40:06 +0100 Subject: [PATCH] Plugin interface simplified. --- .../Squidex.SamplePlugin/SamplePlugin.cs} | 16 ++-- .../Squidex.SamplePlugin.csproj | 20 +++++ .../Plugins/PluginLoaders.cs | 24 +----- .../Plugins/PluginManager.cs | 78 +++++++++++-------- .../Squidex.Infrastructure.csproj | 4 +- .../Pipeline/Plugins/PluginExtensions.cs | 43 +++------- backend/src/Squidex/Squidex.csproj | 1 - backend/src/Squidex/Startup.cs | 3 - 8 files changed, 92 insertions(+), 97 deletions(-) rename backend/{src/Squidex.Infrastructure/Plugins/IWebPlugin.cs => extensions/Squidex.SamplePlugin/SamplePlugin.cs} (50%) create mode 100644 backend/extensions/Squidex.SamplePlugin/Squidex.SamplePlugin.csproj rename backend/src/{Squidex/Pipeline => Squidex.Infrastructure}/Plugins/PluginLoaders.cs (74%) diff --git a/backend/src/Squidex.Infrastructure/Plugins/IWebPlugin.cs b/backend/extensions/Squidex.SamplePlugin/SamplePlugin.cs similarity index 50% rename from backend/src/Squidex.Infrastructure/Plugins/IWebPlugin.cs rename to backend/extensions/Squidex.SamplePlugin/SamplePlugin.cs index 0fb417b3a..c12b5ce22 100644 --- a/backend/src/Squidex.Infrastructure/Plugins/IWebPlugin.cs +++ b/backend/extensions/Squidex.SamplePlugin/SamplePlugin.cs @@ -5,14 +5,18 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Microsoft.AspNetCore.Builder; +using System; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Squidex.Infrastructure.Plugins; -namespace Squidex.Infrastructure.Plugins +namespace Squidex.SamplePlugin { - public interface IWebPlugin : IPlugin + public sealed class SamplePlugin : IPlugin { - void ConfigureBefore(IApplicationBuilder app); - - void ConfigureAfter(IApplicationBuilder app); + public void ConfigureServices(IServiceCollection services, IConfiguration config) + { + throw new NotImplementedException(); + } } } diff --git a/backend/extensions/Squidex.SamplePlugin/Squidex.SamplePlugin.csproj b/backend/extensions/Squidex.SamplePlugin/Squidex.SamplePlugin.csproj new file mode 100644 index 000000000..fd84a73aa --- /dev/null +++ b/backend/extensions/Squidex.SamplePlugin/Squidex.SamplePlugin.csproj @@ -0,0 +1,20 @@ + + + netcoreapp3.0 + 8.0 + + + + + + + + + + + ..\..\Squidex.ruleset + + + + + diff --git a/backend/src/Squidex/Pipeline/Plugins/PluginLoaders.cs b/backend/src/Squidex.Infrastructure/Plugins/PluginLoaders.cs similarity index 74% rename from backend/src/Squidex/Pipeline/Plugins/PluginLoaders.cs rename to backend/src/Squidex.Infrastructure/Plugins/PluginLoaders.cs index d2471144f..d988b42e0 100644 --- a/backend/src/Squidex/Pipeline/Plugins/PluginLoaders.cs +++ b/backend/src/Squidex.Infrastructure/Plugins/PluginLoaders.cs @@ -8,32 +8,14 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Reflection; using McMaster.NETCore.Plugins; -using Squidex.Domain.Apps.Core; -using Squidex.Domain.Apps.Entities; -using Squidex.Domain.Apps.Events; -using Squidex.Infrastructure; -using Squidex.Infrastructure.Plugins; -using Squidex.Web; -namespace Squidex.Pipeline.Plugins +namespace Squidex.Infrastructure.Plugins { public static class PluginLoaders { - private static readonly Type[] SharedTypes = - { - typeof(IPlugin), - typeof(SquidexCoreModel), - typeof(SquidexCoreOperations), - typeof(SquidexEntities), - typeof(SquidexEvents), - typeof(SquidexInfrastructure), - typeof(SquidexWeb) - }; - - public static PluginLoader? LoadPlugin(string pluginPath) + public static PluginLoader? LoadPlugin(string pluginPath, AssemblyName[] sharedAssemblies) { foreach (var candidate in GetPaths(pluginPath)) { @@ -43,7 +25,7 @@ namespace Squidex.Pipeline.Plugins { config.PreferSharedTypes = true; - config.SharedAssemblies.AddRange(SharedTypes.Select(x => x.Assembly.GetName())); + config.SharedAssemblies.AddRange(sharedAssemblies); }); } } diff --git a/backend/src/Squidex.Infrastructure/Plugins/PluginManager.cs b/backend/src/Squidex.Infrastructure/Plugins/PluginManager.cs index dd14f3ca3..5d1132e37 100644 --- a/backend/src/Squidex.Infrastructure/Plugins/PluginManager.cs +++ b/backend/src/Squidex.Infrastructure/Plugins/PluginManager.cs @@ -7,29 +7,69 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Reflection; -using Microsoft.AspNetCore.Builder; +using McMaster.NETCore.Plugins; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Squidex.Infrastructure.Log; namespace Squidex.Infrastructure.Plugins { - public sealed class PluginManager + public sealed class PluginManager : DisposableObjectBase { + private readonly HashSet pluginLoaders = new HashSet(); private readonly HashSet loadedPlugins = new HashSet(); private readonly List<(string Plugin, string Action, Exception Exception)> exceptions = new List<(string, string, Exception)>(); - public IReadOnlyCollection Plugins + protected override void DisposeObject(bool disposing) { - get { return loadedPlugins; } + if (disposing) + { + foreach (var loader in pluginLoaders) + { + loader.Dispose(); + } + } } - public void Add(string name, Assembly assembly) + public Assembly? Load(string path, AssemblyName[] sharedAssemblies) { - Guard.NotNull(assembly); + Guard.NotNullOrEmpty(path); + Guard.NotNull(sharedAssemblies); + + Assembly? assembly = null; + + var loader = PluginLoaders.LoadPlugin(path, sharedAssemblies); + + if (loader != null) + { + try + { + assembly = loader.LoadDefaultAssembly(); + + Add(path, assembly); + + pluginLoaders.Add(loader); + } + catch (Exception ex) + { + LogException(path, "LoadingAssembly", ex); + + loader.Dispose(); + } + } + else + { + LogException(path, "LoadingPlugin", new FileNotFoundException($"Cannot find plugin at {path}")); + } + return assembly; + } + + private void Add(string name, Assembly assembly) + { var pluginTypes = assembly.GetTypes() .Where(t => typeof(IPlugin).IsAssignableFrom(t)) @@ -50,12 +90,8 @@ namespace Squidex.Infrastructure.Plugins } } - public void LogException(string plugin, string action, Exception exception) + private void LogException(string plugin, string action, Exception exception) { - Guard.NotNull(plugin); - Guard.NotNull(action); - Guard.NotNull(exception); - exceptions.Add((plugin, action, exception)); } @@ -70,26 +106,6 @@ namespace Squidex.Infrastructure.Plugins } } - public void ConfigureBefore(IApplicationBuilder app) - { - Guard.NotNull(app); - - foreach (var plugin in loadedPlugins.OfType()) - { - plugin.ConfigureBefore(app); - } - } - - public void ConfigureAfter(IApplicationBuilder app) - { - Guard.NotNull(app); - - foreach (var plugin in loadedPlugins.OfType()) - { - plugin.ConfigureAfter(app); - } - } - public void Log(ISemanticLog log) { Guard.NotNull(log); diff --git a/backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj b/backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj index ea46d3593..259d1ff70 100644 --- a/backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj +++ b/backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj @@ -8,11 +8,9 @@ full True - - - + diff --git a/backend/src/Squidex/Pipeline/Plugins/PluginExtensions.cs b/backend/src/Squidex/Pipeline/Plugins/PluginExtensions.cs index cab52c7fa..cebb20c00 100644 --- a/backend/src/Squidex/Pipeline/Plugins/PluginExtensions.cs +++ b/backend/src/Squidex/Pipeline/Plugins/PluginExtensions.cs @@ -6,7 +6,8 @@ // ========================================================================== using System; -using System.IO; +using System.Linq; +using System.Reflection; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -17,6 +18,12 @@ namespace Squidex.Pipeline.Plugins { public static class PluginExtensions { + private static readonly AssemblyName[] SharedAssemblies = + Assembly.GetEntryAssembly()! + .GetReferencedAssemblies() + .Where(x => x.Name?.StartsWith("Squidex.", StringComparison.OrdinalIgnoreCase) == true) + .ToArray(); + public static IMvcBuilder AddSquidexPlugins(this IMvcBuilder mvcBuilder, IConfiguration config) { var pluginManager = new PluginManager(); @@ -27,25 +34,11 @@ namespace Squidex.Pipeline.Plugins { foreach (var path in options.Plugins) { - var plugin = PluginLoaders.LoadPlugin(path); - - if (plugin != null) - { - try - { - var pluginAssembly = plugin.LoadDefaultAssembly(); + var pluginAssembly = pluginManager.Load(path, SharedAssemblies); - pluginAssembly.AddParts(mvcBuilder); - pluginManager.Add(path, pluginAssembly); - } - catch (Exception ex) - { - pluginManager.LogException(path, "LoadingAssembly", ex); - } - } - else + if (pluginAssembly != null) { - pluginManager.LogException(path, "LoadingPlugin", new FileNotFoundException($"Cannot find plugin at {path}")); + pluginAssembly.AddParts(mvcBuilder); } } } @@ -57,20 +50,6 @@ namespace Squidex.Pipeline.Plugins return mvcBuilder; } - public static void UsePluginsBefore(this IApplicationBuilder app) - { - var pluginManager = app.ApplicationServices.GetRequiredService(); - - pluginManager.ConfigureBefore(app); - } - - public static void UsePluginsAfter(this IApplicationBuilder app) - { - var pluginManager = app.ApplicationServices.GetRequiredService(); - - pluginManager.ConfigureAfter(app); - } - public static void UsePlugins(this IApplicationBuilder app) { var pluginManager = app.ApplicationServices.GetRequiredService(); diff --git a/backend/src/Squidex/Squidex.csproj b/backend/src/Squidex/Squidex.csproj index 2a7c868f4..d6b3a5bef 100644 --- a/backend/src/Squidex/Squidex.csproj +++ b/backend/src/Squidex/Squidex.csproj @@ -38,7 +38,6 @@ - diff --git a/backend/src/Squidex/Startup.cs b/backend/src/Squidex/Startup.cs index 1e9cb14d7..c15572b4c 100644 --- a/backend/src/Squidex/Startup.cs +++ b/backend/src/Squidex/Startup.cs @@ -71,8 +71,6 @@ namespace Squidex public void Configure(IApplicationBuilder app) { - app.UsePluginsBefore(); - app.UseSquidexHealthCheck(); app.UseSquidexRobotsTxt(); app.UseSquidexTracking(); @@ -86,7 +84,6 @@ namespace Squidex app.ConfigureIdentityServer(); app.ConfigureFrontend(); - app.UsePluginsAfter(); app.UsePlugins(); } }