插件基础组件初步开发完成

This commit is contained in:
FalconFly 2023-11-16 11:04:22 +08:00
parent 7dc6d60897
commit 256c00cfe2
8 changed files with 208 additions and 91 deletions

View File

@ -0,0 +1,59 @@
using System.IO;
using System.Reflection;
using System.Runtime.Loader;
namespace Falcon.SugarApi.Plugin
{
/// <summary>
/// 加载程序集帮助方法
/// </summary>
public static class AssemblyLoadHelp
{
/// <summary>
/// 加载到当前域程序集
/// </summary>
/// <param name="assemblyPath">程序集路径</param>
/// <returns></returns>
public static Assembly AssemblyLoad(string assemblyPath) {
return Assembly.LoadFrom(assemblyPath);
}
/// <summary>
/// 使用ALC加载程序集
/// </summary>
/// <param name="assemblyPath">程序集路径</param>
/// <returns>程序集</returns>
public static Assembly ALCLoad(string assemblyPath) {
var context = new AssemblyLoadContext(assemblyPath);
return context.LoadFromAssemblyPath(assemblyPath);
}
/// <summary>
/// 获取程序集的加载上下文AssemblyLoadContext
/// </summary>
/// <param name="assembly">程序集</param>
/// <returns>加载上下文</returns>
public static AssemblyLoadContext? GetAssemblyLoadContext(Assembly assembly) {
return AssemblyLoadContext.GetLoadContext(assembly);
}
/// <summary>
/// 使用alc加载程序集到内存避免程序集文件被锁定
/// </summary>
/// <param name="assemblyPath">程序集路径</param>
/// <returns>程序集</returns>
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);
}
/// <summary>
/// 卸载alc所有加载的程序集将一同卸载
/// </summary>
/// <param name="context">ALC上下文</param>
public static void ALCUnload(AssemblyLoadContext context) {
context.Unload();
}
}
}

View File

@ -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
{
/// <summary>
/// 服务扩展 客户端调用
/// </summary>
public static class IServiceCollectionExtend
{
/// <summary>
/// 注册当前程序集中的控制器
/// </summary>
/// <param name="services">服务集合</param>
/// <returns>服务集合</returns>
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;
}
/// <summary>
/// 注册后台背景任务
/// </summary>
/// <typeparam name="T">任务类型</typeparam>
/// <param name="services">服务集合</param>
/// <returns>服务集合</returns>
public static IServiceCollection AddPluginsBackTask<T>(this IServiceCollection services)
where T : BackgroundLongTask => services.AddHostedService<T>();
/// <summary>
/// 注册插件配置
/// </summary>
/// <typeparam name="T">配置类型</typeparam>
/// <param name="services">服务集合</param>
/// <param name="options">配置实体</param>
/// <returns>服务集合</returns>
public static IServiceCollection AddPluginOption<T>(this IServiceCollection services,T options)
where T : class => services.AddSingleton(options);
/// <summary>
/// 注册插件配置
/// </summary>
/// <typeparam name="T">配置类型</typeparam>
/// <param name="services">服务集合</param>
/// <param name="config">可选,应用配置节点</param>
/// <param name="optionBuilder">可选,配置创建器</param>
/// <returns>服务集合</returns>
public static IServiceCollection AddPluginOption<T>(this IServiceCollection services,IConfigurationSection? config,Action<T>? optionBuilder)
where T : class, new() {
var options = config == null ? new T() : config.Get<T>();
options = options ?? throw new Exception("Get Options fail!");
optionBuilder?.Invoke(options);
return services.AddPluginOption(options);
}
}
}

View File

@ -0,0 +1 @@
## 插件客户端方法

View File

@ -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
{
/// <summary>
/// 查找插件服务
/// </summary>
public static class FindPluginService
{
/// <summary>
/// 查找并增加插件服务
/// </summary>
/// <param name="assemblyFile">程序集名称</param>
/// <param name="services">服务集合</param>
/// <param name="configuration">配置</param>
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);
}
/// <summary>
/// 查找并增加插件服务
/// </summary>
/// <param name="assembly">程序集</param>
/// <param name="services">服务集合</param>
/// <param name="configuration">配置</param>
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);
}
}
}
}

View File

@ -1,19 +0,0 @@
using System.Collections.Generic;
namespace Falcon.SugarApi.Plugin
{
/// <summary>
/// 插件设置
/// </summary>
public class PluginSetting
{
/// <summary>
/// 插件名称
/// </summary>
public string name { get; set; }
/// <summary>
/// 插件文件
/// </summary>
public string file { get; set; }
}
}

View File

@ -1,9 +0,0 @@
using System.Collections.Generic;
namespace Falcon.SugarApi.Plugin
{
/// <summary>
/// 插件设置列表
/// </summary>
public class PluginSettingList:List<PluginSetting> { }
}

View File

@ -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
{
/// <summary>
/// 服务扩展 服务端调用
/// </summary>
public static class IServiceCollectionExtend
{
/// <summary>
/// 注册插件。
/// <para>查找插件中的IServicePlugin实现并运行其中的AddServices方法注册和初始化插件</para>
/// </summary>
/// <param name="services">服务集合</param>
/// <param name="config">应用程序配置</param>
/// <param name="pluginNames">插件名称数组</param>
/// <returns>服务集合</returns>
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;
}
/// <summary>
/// 注册插件中的控制器。一般由插件自行注册。
/// </summary>
/// <param name="services">服务集合</param>
/// <param name="assemblyPath">插件程序集文件路径</param>
/// <returns>服务集合</returns>
public static IServiceCollection AddPluginsController(this IServiceCollection services,string assemblyPath) {
var pluginAssembly = Assembly.LoadFrom(assemblyPath);
return services.AddPluginsController(pluginAssembly);
}
/// <summary>
/// 注册插件中的控制器。一般由插件自行注册。
/// </summary>
/// <param name="services">服务集合</param>
/// <param name="assembly">插件程序集</param>
/// <returns>服务集合</returns>
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;
}
}
}

View File

@ -0,0 +1 @@
## 服务端调用方法