コード例 #1
0
ファイル: PluginManager.cs プロジェクト: ym1100/Remember.Core
        /// <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);
        }
コード例 #2
0
 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)
     { }
 }
コード例 #3
0
 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)
     { }
 }
コード例 #4
0
        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);
        }
コード例 #5
0
        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);
        }
コード例 #6
0
        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);
        }
コード例 #7
0
        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);
        }
コード例 #8
0
        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);
        }