/// <summary> /// Load all plugins<br/> /// Flow<br/> /// - Get plugin names from website configuration<br/> /// - Load plugin information from it's directory<br/> /// - Use roslyn compile service compile the source files to assembly<br/> /// - Load compiled assembly<br/> /// - Register types in assembly to IoC container<br/> /// Attention<br/> /// - IPlugin will not initliaze here because we may need initialize database before<br/> /// you should invoke IPlugin manually after calling this method<br/> /// 加载所有插件<br/> /// 流程<br/> /// - 从网站配置获取插件名称列表<br/> /// - 从插件目录加载插件信息<br/> /// - 使用roslyn编译服务编译插件源代码到程序集<br/> /// - 加载编译后的程序集<br/> /// - 注册程序集中的类型到IoC容器<br/> /// 注意<br/> /// - 插件不会在这里初始化, 因为我们可能需要在这之前初始化数据库<br/> /// 你需要在调用这个函数后手动调用IPlugin接口<br/> /// </summary> internal protected virtual void Initialize() { var configManager = Application.Ioc.Resolve <WebsiteConfigManager>(); var pathManager = Application.Ioc.Resolve <LocalPathManager>(); Plugins.Clear(); PluginAssemblies.Clear(); // Get plugin names from website configuration var pluginDirectories = pathManager.GetPluginDirectories(); foreach (var pluginName in configManager.WebsiteConfig.Plugins) { var dir = pluginDirectories .Select(p => PathUtils.SecureCombine(p, pluginName)) .FirstOrDefault(p => Directory.Exists(p)); if (dir == null) { throw new DirectoryNotFoundException($"Plugin directory of {pluginName} not found"); } var info = PluginInfo.FromDirectory(dir); if (ShouldLoadPlugin(info)) { Plugins.Add(info); } } // Load plugins var assemblyLoader = Application.Ioc.Resolve <IAssemblyLoader>(); foreach (var plugin in Plugins) { // Compile plugin plugin.Compile(); // Load compiled assembly, some plugin may not have an assembly var assemblyPath = plugin.AssemblyPath(); if (File.Exists(assemblyPath)) { // .NET will cache assembly by path, so if assembly contents changed // after plugin recompile, LoadFile will still use the old assembly, // we should load bytes instead of path to avoid caching. var assembly = assemblyLoader.Load(File.ReadAllBytes(assemblyPath)); plugin.Assembly = assembly; PluginAssemblies.Add(assembly); PluginAssemblyPathes.Add(assemblyPath); } } // Register types in assembly to IoC container // Only public types will be registered foreach (var assembly in PluginAssemblies) { var types = assembly.GetTypes().Where(t => t.IsPublic); Application.Ioc.RegisterExports(types); } }
private void AddAssembly(CrmPluginAssembly crmPluginAssembly) { PluginAssemblies.Add(crmPluginAssembly); }
/// <summary> /// Loads the given Core plugin and any other available plugins, if supported by the environment. /// </summary> /// <param name="core">The core plugin that controls the environment.</param> /// <remarks> /// Misc things this function does: /// - Delete files scheduled for deletion /// - Install pending extensions /// </remarks> /// <exception cref="ArgumentNullException">Thrown if <paramref name="core"/> is null.</exception> public virtual async Task LoadCore(CoreSkyEditorPlugin core) { if (core == null) { throw new ArgumentNullException(nameof(core)); } // Load providers CurrentFileSystem = core.GetFileSystem(); CurrentSettingsProvider = core.GetSettingsProvider(this); CurrentConsoleProvider = core.GetConsoleProvider(); // Delete files and directories scheduled for deletion await DeleteScheduledFiles(CurrentSettingsProvider, CurrentFileSystem); // Install pending extensions ExtensionDirectory = core.GetExtensionDirectory(); await ExtensionHelper.InstallPendingExtensions(ExtensionDirectory, this); // Load the provided core CorePluginAssembly = core.GetType().GetTypeInfo().Assembly; Plugins.Add(core); core.Load(this); // Load plugins, if enabled if (core.IsPluginLoadingEnabled()) { // Get the paths of all plugins to be loaded var supportedPlugins = GetPluginPaths(); // Load the plugin assemblies foreach (var item in supportedPlugins) { try { var assemblyActual = core.LoadAssembly(item); if (assemblyActual != null) { PluginAssemblies.Add(assemblyActual); foreach (var plg in assemblyActual.DefinedTypes.Where((x) => ReflectionHelpers.IsOfType(x, typeof(SkyEditorPlugin).GetTypeInfo()) && this.CanCreateInstance(x))) { Plugins.Add(this.CreateInstance(plg) as SkyEditorPlugin); } } } catch (FileLoadException) { // The assembly is a bad assembly. We can continue loading plugins, but not with this FailedPluginLoads.Add(item); } catch (BadImageFormatException) { // The assembly is a bad assembly. We can continue loading plugins, but not with this FailedPluginLoads.Add(item); } catch (NotSupportedException) { // The current environment does not support loading assemblies this way. // Abort dynamic assembly loading break; } } } // Load logical plugins PluginsLoading?.Invoke(this, new EventArgs()); var coreType = core.GetType(); foreach (var item in Plugins.Where(p => p.GetType() != core.GetType())) { item.Load(this); } // Load dependant plugins while (DependantPluginLoadingQueue.Count > 0) { var item = DependantPluginLoadingQueue.Dequeue(); var pluginType = item.GetType(); // Determine if it has already been loaded if (!Plugins.Where((x) => x.GetType() == pluginType).Any()) { // Add the plugin Plugins.Add(item); // Add the assembly if it hasn't been added already var pluginAssembly = pluginType.GetTypeInfo().Assembly; if (!PluginAssemblies.Contains(pluginAssembly)) { PluginAssemblies.Add(pluginAssembly); } // Load the plugin item.Load(this); } } // Use reflection to fill the type registry if (core.IsCorePluginAssemblyDynamicTypeLoadEnabled()) { LoadTypes(CorePluginAssembly); } if (core.IsExtraPluginAssemblyDynamicTypeLoadEnabled()) { foreach (var item in PluginAssemblies) { LoadTypes(item); } } PluginLoadComplete?.Invoke(this, new EventArgs()); }