diff --git a/Falcon.SugarApi/Plugin/AssemblyLoadHelp.cs b/Falcon.SugarApi/Plugin/AssemblyLoadHelp.cs new file mode 100644 index 0000000..7962033 --- /dev/null +++ b/Falcon.SugarApi/Plugin/AssemblyLoadHelp.cs @@ -0,0 +1,59 @@ +using System.IO; +using System.Reflection; +using System.Runtime.Loader; + +namespace Falcon.SugarApi.Plugin +{ + /// + /// 加载程序集帮助方法 + /// + public static class AssemblyLoadHelp + { + /// + /// 加载到当前域程序集 + /// + /// 程序集路径 + /// + public static Assembly AssemblyLoad(string assemblyPath) { + return Assembly.LoadFrom(assemblyPath); + } + /// + /// 使用ALC加载程序集 + /// + /// 程序集路径 + /// 程序集 + public static Assembly ALCLoad(string assemblyPath) { + var context = new AssemblyLoadContext(assemblyPath); + return context.LoadFromAssemblyPath(assemblyPath); + } + + /// + /// 获取程序集的加载上下文AssemblyLoadContext + /// + /// 程序集 + /// 加载上下文 + public static AssemblyLoadContext? GetAssemblyLoadContext(Assembly assembly) { + return AssemblyLoadContext.GetLoadContext(assembly); + } + + /// + /// 使用alc加载程序集到内存,避免程序集文件被锁定 + /// + /// 程序集路径 + /// 程序集 + public static Assembly ALCLoadInMemory(string assemblyPath) { + var bys = File.ReadAllBytes(assemblyPath); + var stream = new MemoryStream(bys); + var alc = new AssemblyLoadContext(assemblyPath); + return alc.LoadFromStream(stream); + } + + /// + /// 卸载alc,所有加载的程序集将一同卸载 + /// + /// ALC上下文 + public static void ALCUnload(AssemblyLoadContext context) { + context.Unload(); + } + } +} diff --git a/Falcon.SugarApi/Plugin/Client/IServiceCollectionExtend.cs b/Falcon.SugarApi/Plugin/Client/IServiceCollectionExtend.cs new file mode 100644 index 0000000..81a3b85 --- /dev/null +++ b/Falcon.SugarApi/Plugin/Client/IServiceCollectionExtend.cs @@ -0,0 +1,67 @@ +using Falcon.SugarApi.BackTask; +using Microsoft.AspNetCore.Mvc.ApplicationParts; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace Falcon.SugarApi.Plugin.Client +{ + /// + /// 服务扩展 客户端调用 + /// + public static class IServiceCollectionExtend + { + /// + /// 注册当前程序集中的控制器 + /// + /// 服务集合 + /// 服务集合 + public static IServiceCollection AddPluginsController(this IServiceCollection services) { + var pluginAssembly = Assembly.GetExecutingAssembly(); + var part = new AssemblyPart(pluginAssembly); + services.AddControllers().ConfigureApplicationPartManager(apm => { + if(!apm.ApplicationParts.Contains(part)) { + apm.ApplicationParts.Add(part); + } + }); + return services; + } + + /// + /// 注册后台背景任务 + /// + /// 任务类型 + /// 服务集合 + /// 服务集合 + public static IServiceCollection AddPluginsBackTask(this IServiceCollection services) + where T : BackgroundLongTask => services.AddHostedService(); + + /// + /// 注册插件配置 + /// + /// 配置类型 + /// 服务集合 + /// 配置实体 + /// 服务集合 + public static IServiceCollection AddPluginOption(this IServiceCollection services,T options) + where T : class => services.AddSingleton(options); + + /// + /// 注册插件配置 + /// + /// 配置类型 + /// 服务集合 + /// 可选,应用配置节点 + /// 可选,配置创建器 + /// 服务集合 + public static IServiceCollection AddPluginOption(this IServiceCollection services,IConfigurationSection? config,Action? optionBuilder) + where T : class, new() { + var options = config == null ? new T() : config.Get(); + options = options ?? throw new Exception("Get Options fail!"); + optionBuilder?.Invoke(options); + return services.AddPluginOption(options); + } + } +} diff --git a/Falcon.SugarApi/Plugin/Client/Readme.md b/Falcon.SugarApi/Plugin/Client/Readme.md new file mode 100644 index 0000000..7749c95 --- /dev/null +++ b/Falcon.SugarApi/Plugin/Client/Readme.md @@ -0,0 +1 @@ +## ͻ˷ \ No newline at end of file diff --git a/Falcon.SugarApi/Plugin/FindPluginService.cs b/Falcon.SugarApi/Plugin/FindPluginService.cs deleted file mode 100644 index 5c84167..0000000 --- a/Falcon.SugarApi/Plugin/FindPluginService.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using System; -using System.IO; -using System.Reflection; -using System.Runtime.Loader; - -namespace Falcon.SugarApi.Plugin -{ - /// - /// 查找插件服务 - /// - public static class FindPluginService - { - /// - /// 查找并增加插件服务 - /// - /// 程序集名称 - /// 服务集合 - /// 配置 - public static void FindAddPluginService(string assemblyFile,IServiceCollection services,IConfiguration configuration) { - if(!File.Exists(assemblyFile)) { - throw new FileNotFoundException($"插件文件没有找到:{assemblyFile}"); - } - //var doMain = AppDomain.CurrentDomain; - //var assembly = doMain.Load(assemblyFile); - - var dm = new AssemblyLoadContext(null,false); - var assembly = dm.LoadFromAssemblyPath(assemblyFile); - - FindAddPluginService(assembly,services,configuration); - } - /// - /// 查找并增加插件服务 - /// - /// 程序集 - /// 服务集合 - /// 配置 - public static void FindAddPluginService(Assembly assembly,IServiceCollection services,IConfiguration configuration) { - var name = typeof(IServicePlugin).FullName; - if(name == null) { - return; - } - foreach(Type type in assembly.GetTypes()) { - if(type == null || !type.IsPublic) { - continue; - } - if(type.GetInterface(name) == null) { - continue; - } - var tname = type.FullName; - if(tname == null) { - continue; - } - var obj = type.Assembly.CreateInstance(tname) as IServicePlugin; - if(obj == null) { - continue; - } - obj.AddServices(services,configuration); - } - } - } -} diff --git a/Falcon.SugarApi/Plugin/PluginSetting.cs b/Falcon.SugarApi/Plugin/PluginSetting.cs deleted file mode 100644 index 345b8ce..0000000 --- a/Falcon.SugarApi/Plugin/PluginSetting.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Collections.Generic; - -namespace Falcon.SugarApi.Plugin -{ - /// - /// 插件设置 - /// - public class PluginSetting - { - /// - /// 插件名称 - /// - public string name { get; set; } - /// - /// 插件文件 - /// - public string file { get; set; } - } -} diff --git a/Falcon.SugarApi/Plugin/PluginSettingList.cs b/Falcon.SugarApi/Plugin/PluginSettingList.cs deleted file mode 100644 index 4976003..0000000 --- a/Falcon.SugarApi/Plugin/PluginSettingList.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Collections.Generic; - -namespace Falcon.SugarApi.Plugin -{ - /// - /// 插件设置列表 - /// - public class PluginSettingList:List { } -} diff --git a/Falcon.SugarApi/Plugin/Service/IServiceCollectionExtend.cs b/Falcon.SugarApi/Plugin/Service/IServiceCollectionExtend.cs new file mode 100644 index 0000000..cfafb95 --- /dev/null +++ b/Falcon.SugarApi/Plugin/Service/IServiceCollectionExtend.cs @@ -0,0 +1,80 @@ +using Microsoft.AspNetCore.Mvc.ApplicationParts; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Falcon.SugarApi.Plugin.Service +{ + /// + /// 服务扩展 服务端调用 + /// + public static class IServiceCollectionExtend + { + /// + /// 注册插件。 + /// 查找插件中的IServicePlugin实现,并运行其中的AddServices方法注册和初始化插件 + /// + /// 服务集合 + /// 应用程序配置 + /// 插件名称数组 + /// 服务集合 + public static IServiceCollection AddPluginService(this IServiceCollection services,IConfiguration config,params string[] pluginNames) { + var name = typeof(IServicePlugin).FullName; + if(name == null) { + return services; + } + foreach(var pluginName in pluginNames) { + var pa = AssemblyLoadHelp.ALCLoad(pluginName); + foreach(Type type in pa.GetTypes()) { + if(type == null || !type.IsPublic || type.GetInterface(name) == null) { + continue; + } + var tname = type.FullName; + if(tname == null) { + continue; + } + if(type.Assembly.CreateInstance(tname) is not IServicePlugin obj) { + continue; + } + obj.AddServices(services,config); + } + + } + return services; + } + + /// + /// 注册插件中的控制器。一般由插件自行注册。 + /// + /// 服务集合 + /// 插件程序集文件路径 + /// 服务集合 + public static IServiceCollection AddPluginsController(this IServiceCollection services,string assemblyPath) { + var pluginAssembly = Assembly.LoadFrom(assemblyPath); + return services.AddPluginsController(pluginAssembly); + } + + /// + /// 注册插件中的控制器。一般由插件自行注册。 + /// + /// 服务集合 + /// 插件程序集 + /// 服务集合 + public static IServiceCollection AddPluginsController(this IServiceCollection services,Assembly assembly) { + var part = new AssemblyPart(assembly); + services.AddControllers().ConfigureApplicationPartManager(apm => { + if(!apm.ApplicationParts.Contains(part)) { + apm.ApplicationParts.Add(part); + } + }); + return services; + } + + } +} diff --git a/Falcon.SugarApi/Plugin/Service/Readme.md b/Falcon.SugarApi/Plugin/Service/Readme.md new file mode 100644 index 0000000..2bea63b --- /dev/null +++ b/Falcon.SugarApi/Plugin/Service/Readme.md @@ -0,0 +1 @@ +## ˵÷ \ No newline at end of file