/// <summary> /// 加载插件程序集 /// </summary> /// <param name="pluginId"></param> public void LoadPlugin(string pluginId) { // 此插件的 加载上下文 var context = new CollectibleAssemblyLoadContext(); #region 加载插件主dll // 插件的主dll, 不包括插件项目引用的dll string pluginMainDllFilePath = Path.Combine(PluginPathProvider.PluginsRootPath(), pluginId, $"{pluginId}.dll"); Assembly pluginMainAssembly; using (var fs = new FileStream(pluginMainDllFilePath, FileMode.Open)) { // 使用此方法, 就不会导致dll被锁定 pluginMainAssembly = context.LoadFromStream(fs); // 加载其中的控制器 _pluginControllerManager.AddControllers(pluginMainAssembly); } #endregion // TODO:未测试 加载插件引用的dll: 方法二: //AssemblyName[] referenceAssemblyNames = pluginMainAssembly.GetReferencedAssemblies(); //foreach (var assemblyName in referenceAssemblyNames) //{ // context.LoadFromAssemblyName(assemblyName); //} // TODO: 跳过不需要加载的 dll, eg: ASP.NET Core Shared Framework, 主程序中已有dll string[] skipDlls = new string[] { "Core.dll", "Domain.dll", "Framework.dll", "Services.dll", "Repositories.dll", "PluginCore.dll" }; #region 加载插件引用的dll // 加载插件引用的dll // eg: xxx/Plugins/HelloWorld string pluginDirPath = Path.Combine(PluginPathProvider.PluginsRootPath(), pluginId); var pluginDir = new DirectoryInfo(pluginDirPath); // 插件引用的所有dll (排除 主dll 和 skipDlls ) // 注意: 主程序中已有dll 必须跳过, 应为这些默认Context中已经加载, 而如果插件Context再次加载, 则认为这两个是不同Assembly, 导致其中的Type转换失败 // 这里简单来说,意思就是当在一个自定义LoadContext中加载程序集的时候,如果找不到这个程序集,程序会自动去默认LoadContext中查找,如果默认LoadContext中都找不到,就会返回null。 // 这里我突然想到会不会是因为DemoPlugin1、DemoPlugin2以及主站点的AssemblyLoadContext都加载了Mystique.Core.dll程序集的缘故,虽然他们加载的是同一个程序集,但是因为LoadContext不同,所以系统认为它是2个程序集。 // 参考: https://www.cnblogs.com/lwqlun/p/12930713.html var allReferenceFileInfos = pluginDir.GetFiles("*.dll").Where(p => p.Name != $"{pluginId}.dll" && !skipDlls.Contains(p.Name)); foreach (FileInfo file in allReferenceFileInfos) { using (var sr = new StreamReader(file.OpenRead())) { context.LoadFromStream(sr.BaseStream); } } #endregion // 这个插件加载上下文 放入 集合中 PluginsLoadContexts.Add(pluginId, context); }
public static void Save(string pluginSettingsJsonStr, string pluginId) { if (pluginSettingsJsonStr == null) { throw new ArgumentNullException(nameof(pluginSettingsJsonStr)); } try { string pluginSettingsFilePath = Path.Combine(PluginPathProvider.PluginsRootPath(), pluginId, SettingsFile); //File.WriteAllText(pluginSettingsFilePath, pluginSettingsJsonStr, Encoding.UTF8); // 写的时候加缩进 File.WriteAllText(pluginSettingsFilePath, ConvertJsonString(pluginSettingsJsonStr), Encoding.UTF8); } catch (Exception ex) { } }
public static void Save <T>(T pluginSettingsModel, string pluginId) where T : PluginSettingsModel { if (pluginSettingsModel == null) { throw new ArgumentNullException(nameof(pluginSettingsModel)); } try { string pluginSettingsJsonStr = System.Text.Json.JsonSerializer.Serialize <T>(pluginSettingsModel); string pluginSettingsFilePath = Path.Combine(PluginPathProvider.PluginsRootPath(), pluginId, SettingsFile); //File.WriteAllText(pluginSettingsFilePath, pluginSettingsJsonStr, Encoding.UTF8); // 写的时候加缩进 File.WriteAllText(pluginSettingsFilePath, ConvertJsonString(pluginSettingsJsonStr), Encoding.UTF8); } catch (Exception ex) { } }
public static IList <PluginInfoModel> CreateAll() { IList <PluginInfoModel> pluginInfoModels = new List <PluginInfoModel>(); IList <string> pluginDirs = PluginPathProvider.AllPluginDir(); foreach (var dir in pluginDirs) { // 从 dir 中解析出 pluginId // 约定: 插件文件夹名=PluginID=插件主.dll string pluginId = PluginPathProvider.GetPluginFolderNameByDir(dir); PluginInfoModel model = Create(pluginId); pluginInfoModels.Add(model); } // 去除为 null: 目标插件信息不存在,或者格式错误的 pluginInfoModels = pluginInfoModels.Where(m => m != null).ToList(); return(pluginInfoModels); }
public static string Create (string pluginId) { string rtnStr = string.Empty; string pluginDir = Path.Combine(PluginPathProvider.PluginsRootPath(), pluginId); string pluginSettingsFilePath = Path.Combine(pluginDir, SettingsFile); if (!File.Exists(pluginSettingsFilePath)) { return(null); } try { rtnStr = File.ReadAllText(pluginSettingsFilePath, Encoding.UTF8); } catch (Exception ex) { rtnStr = null; } return(rtnStr); }
public static PluginReadmeModel Create(string pluginId) { PluginReadmeModel readmeModel = new PluginReadmeModel(); string pluginDir = Path.Combine(PluginPathProvider.PluginsRootPath(), pluginId); string pluginReadmeFilePath = Path.Combine(pluginDir, ReadmeFile); if (!File.Exists(pluginReadmeFilePath)) { return(null); } try { string readmeStr = File.ReadAllText(pluginReadmeFilePath, Encoding.UTF8); readmeModel.PluginId = pluginId; readmeModel.Content = readmeStr; } catch (Exception ex) { readmeModel = null; } return(readmeModel); }
public static T Create <T> (string pluginId) where T : PluginSettingsModel { PluginSettingsModel rtnModel = new PluginSettingsModel(); string pluginDir = Path.Combine(PluginPathProvider.PluginsRootPath(), pluginId); string pluginSettingsFilePath = Path.Combine(pluginDir, SettingsFile); if (!File.Exists(pluginSettingsFilePath)) { return(null); } try { string settingsStr = File.ReadAllText(pluginSettingsFilePath, Encoding.UTF8); rtnModel = System.Text.Json.JsonSerializer.Deserialize <T>(settingsStr); } catch (Exception ex) { rtnModel = null; } return(rtnModel as T); }
public static PluginInfoModel Create(string pluginId) { PluginInfoModel pluginInfoModel = new PluginInfoModel(); string pluginDir = Path.Combine(PluginPathProvider.PluginsRootPath(), pluginId); string pluginInfoFilePath = Path.Combine(pluginDir, InfoJson); if (!File.Exists(pluginInfoFilePath)) { return(null); } try { string pluginInfoJsonStr = File.ReadAllText(pluginInfoFilePath, Encoding.UTF8); JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions(); jsonSerializerOptions.PropertyNameCaseInsensitive = true; pluginInfoModel = JsonSerializer.Deserialize <PluginInfoModel>(pluginInfoJsonStr, jsonSerializerOptions); } catch (Exception ex) { pluginInfoModel = null; } return(pluginInfoModel); }