/// <summary> /// 应用指定的加载配置进行插件加载。 /// </summary> /// <param name="settings">指定的加载配置对象。</param> /// <remarks> /// <para>使用不同的<see cref="Zongsoft.Plugins.PluginLoaderSetup"/>设置项多次加载,会导致最后一次加载覆盖上次加载的插件结构,这有可能会影响您的插件应用对构件或服务的获取路径,从而导致不可预知的结果。</para> /// <para>如果要重用上次加载的配置,请调用无参的Load方法。</para> /// </remarks> /// <exception cref="System.ArgumentNullException">参数<paramref name="settings"/>为空(null)。</exception> public void Load(PluginLoaderSetup settings) { if (settings == null) { throw new ArgumentNullException("settings"); } //激发“Loading”事件 this.OnLoading(new PluginLoadEventArgs(settings)); //如果指定的目录路径不存在则激发“Failure”事件,并退出 if (!Directory.Exists(_settings.PluginsDirectory)) { throw new DirectoryNotFoundException(string.Format("The '{0}' plugins directory is not exists.", _settings.PluginsDirectory)); } //清空插件列表 _plugins.Clear(); //预加载插件目录下的所有插件文件 this.PreloadPluginFiles(_settings.PluginsDirectory, null, settings); //正式加载所有插件 this.LoadPlugins(_plugins, settings); //保存加载配置对象 _settings = settings; //激发“Loaded”事件 this.OnLoaded(new PluginLoadEventArgs(settings)); }
private void LoadPlugins(PluginCollection plugins, PluginLoaderSetup settings) { if (plugins == null || plugins.Count < 1) { return; } var stack = new Stack <Plugin>(); //注意:①. 先加载同级插件 foreach (var plugin in plugins) { //确保同级插件栈内的所有插件一定都是未加载的插件 if (plugin.Status == PluginStatus.Loading) { this.TryPushToStack(plugin, stack); this.LoadPlugin(stack, pluginName => plugins[pluginName], settings); } } //注意:②. 再依次加载各个子插件 foreach (var plugin in plugins) { if (plugin.Status == PluginStatus.Loaded) { this.LoadPlugins(plugin.Children, settings); } } }
public PluginLoadEventArgs(PluginLoaderSetup settings) { if (settings == null) { throw new ArgumentNullException("settings"); } this.Settings = settings; }
public PluginLoadedEventArgs(PluginLoaderSetup settings, Plugin plugin) : base(settings) { if (plugin == null) { throw new ArgumentNullException("plugin"); } this.Plugin = plugin; }
public PluginLoadingEventArgs(PluginLoaderSetup settings, string pluginFile) : base(settings) { if (string.IsNullOrEmpty(pluginFile)) { throw new ArgumentNullException("pluginFile"); } this.PluginFile = pluginFile; }
/// <summary> /// 应用指定的设置加载插件树。 /// </summary> /// <param name="settings">指定的插件加载器配置对象。</param> /// <exception cref="System.ArgumentNullException">参数<paramref name="settings"/>为空(null)。</exception> public void Load(PluginLoaderSetup settings) { if (settings == null) { throw new ArgumentNullException("settings"); } //应用指定的设置进行加载 this.Loader.Load(settings); }
private void PreloadPluginChildrenFiles(string directoryPath, Plugin parent, PluginLoaderSetup settings) { //获取当前插件目录的下级子目录 string[] childDirectoriePaths = Directory.GetDirectories(directoryPath); //依次加载子目录下的所有插件 foreach (string childDirectoryPath in childDirectoriePaths) { this.PreloadPluginFiles(childDirectoryPath, parent, settings); } }
internal PluginLoader(PluginResolver resolver, PluginLoaderSetup setup) { if (resolver == null) { throw new ArgumentNullException("resolver"); } _resolver = resolver; _settings = setup; _plugins = new PluginCollection(); }
private void PreloadPluginFiles(string directoryPath, Plugin parent, PluginLoaderSetup settings) { //获取指定目录下的插件文件 var filePaths = Directory.GetFiles(directoryPath, "*.plugin", SearchOption.TopDirectoryOnly); //如果当前目录下没有插件文件则查找子目录 if (filePaths == null || filePaths.Length < 1) { this.PreloadPluginChildrenFiles(directoryPath, parent, settings); return; } //已经成功加载的主插件列表 var masters = new List <Plugin>(); //注意:取消了对返回的文件名数组进行排序(包含文件扩展名的排序是不准的) //Array.Sort<string>(filePaths, StringComparer.Ordinal); //依次加载所有插件文件 foreach (string filePath in filePaths) { //首先加载插件文件的清单信息(根据清单信息中的依赖插件来决定是否需要完整加载) Plugin plugin = this.LoadPluginManifest(filePath, parent, settings); //如果预加载失败,则跳过以进行下一个插件文件的处理 if (plugin == null || plugin.Status == PluginStatus.Failed) { continue; } //判断当前预加载的插件是否为主插件 if (plugin.IsMaster) { //将当前已完整加载的插件加入主插件列表中 masters.Add(plugin); } } //定义子插件的父插件,默认为当前插件目录的父插件 Plugin ownerPlugin = parent; //如果当前插件目录下有主插件则所有子插件的父为第一个主插件 if (masters.Count > 0) { ownerPlugin = masters[0]; } //预加载子插件 this.PreloadPluginChildrenFiles(directoryPath, ownerPlugin, settings); }
private void LoadPlugins(PluginCollection plugins, PluginLoaderSetup settings) { if (plugins == null || plugins.Count < 1) { return; } Plugin hidden = null; var stack = new Stack <Plugin>(); //注意:①. 先加载同级插件(忽略隐藏式插件) foreach (var plugin in plugins) { //确保同级插件栈内的所有插件一定都是未加载的插件 if (plugin.Status == PluginStatus.Loading) { //如果是隐藏式插件,则先忽略它,放待最后再来加载 if (plugin.IsHidden) { hidden = plugin; } else { this.TryPushToStack(plugin, stack); this.LoadPlugin(stack, pluginName => (plugins.TryGet(pluginName, out var found) ? found : null), settings); } } } //注意:②. 再依次加载各个子插件 foreach (var plugin in plugins) { if (plugin.Status == PluginStatus.Loaded) { this.LoadPlugins(plugin.Children, settings); } } //注意:③. 如果当前层级中含有隐藏式插件,则留待最后再来加载它 if (hidden != null) { this.TryPushToStack(hidden, stack); this.LoadPlugin(stack, pluginName => (plugins.TryGet(pluginName, out var found) ? found : null), settings); } }
private Plugin LoadPluginManifest(string filePath, Plugin parent, PluginLoaderSetup settings) { //激发“PluginLoading”事件 this.OnPluginLoading(new PluginLoadingEventArgs(settings, filePath)); //解析插件清单 Plugin plugin = _resolver.ResolvePluginOnlyManifest(filePath, parent); if (plugin == null) { return(null); } //设置插件状态 plugin.Status = PluginStatus.Loading; if (parent == null) { if (_plugins.Any(p => string.Equals(p.Name, plugin.Name, StringComparison.OrdinalIgnoreCase))) { plugin.Status = PluginStatus.Failed; plugin.StatusDescription = string.Format("The name is '{0}' of plugin was exists. it's path is: '{1}'", plugin.Name, plugin.FilePath); //抛出插件文件异常(原因为插件名称重复) throw new PluginFileException(plugin.FilePath, $"The name is '{plugin.Name}' of plugin was exists. it's path is: '{plugin.FilePath}'"); } //将预加载的插件对象加入到根插件的集合中 _plugins.Add(plugin); } else { //将预加载的插件对象加入到父插件的子集中,如果返回假则表示加载失败 if (!parent.Children.Add(plugin, false)) { plugin.Status = PluginStatus.Failed; plugin.StatusDescription = string.Format("The name is '{0}' of plugin was exists. it's path is: '{1}'", plugin.Name, plugin.FilePath); //抛出插件文件异常(原因为插件名称重复) throw new PluginFileException(plugin.FilePath, $"The name is '{plugin.Name}' of plugin was exists. it's path is: '{plugin.FilePath}'"); } } return(plugin); }
private void LoadPluginContent(Plugin plugin, PluginLoaderSetup settings) { if (plugin == null) { throw new ArgumentNullException("plugin"); } if (plugin.Status != PluginStatus.Loading) { return; } try { //解析插件对象 _resolver.ResolvePluginWithoutManifest(plugin); //设置已加载插件对象所属应用域的私有路径(测试用代码) PluginContainer.SetPrivatePath(plugin.FilePath, AppDomain.CurrentDomain); //设置插件状态 plugin.Status = PluginStatus.Loaded; //激发“PluginLoaded”事件 this.OnPluginLoaded(new PluginLoadedEventArgs(settings, plugin)); } catch (Exception ex) { plugin.Status = PluginStatus.Failed; plugin.StatusDescription = ex.Message; if (plugin.Parent == null) { _plugins.Remove(plugin.Name); } else { plugin.Parent.Children.Remove(plugin.Name); } throw new PluginFileException(plugin.FilePath, $"The '{plugin.FilePath}' plugin file resolve failed.", ex); } }
private void LoadPlugin(Stack <Plugin> stack, Func <string, Plugin> dependencyThunk, PluginLoaderSetup settings) { if (stack == null || stack.Count < 1) { return; } var plugin = stack.Peek(); if (this.IsRequiredLoad(plugin, dependencyThunk)) { this.LoadPluginContent(stack.Pop(), settings); } else { foreach (var dependency in plugin.Manifest.Dependencies) { if (this.IsRequiredLoad(dependency.Plugin, dependencyThunk)) { this.LoadPluginContent(dependency.Plugin, settings); } else { this.TryPushToStack(dependency.Plugin, stack); } } } if (stack.Count > 0) { this.LoadPlugin(stack, dependencyThunk, settings); } }