7.3 KiB
7.3 KiB
source_files, generated_at, model, schema_version, sha256
| source_files | generated_at | model | schema_version | sha256 | ||||
|---|---|---|---|---|---|---|---|---|
|
2026-04-16T04:27:52.597409+00:00 | Qwen/Qwen3-Coder-Next-FP8 | 1 | a022d6fe08f41d94 |
PluginLib
Documentation: Plugin Configuration and Management Module
1. Purpose
This module provides infrastructure for managing plugins in the DataPRO system using Managed Extensibility Framework (MEF). It defines configuration structures for specifying plugin directories, a static configuration accessor (PluginConfig), and a singleton PluginManager responsible for discovering, loading, and resolving plugin assemblies from configured directories. The module enables dynamic plugin discovery and composition at runtime based on MEF exports, while enforcing strict validation of plugin folder paths and thread-safe initialization.
2. Public Interface
PluginConfigData
string[] PluginFolders
Public field annotated with[XmlArrayItem("Folder")]. Holds an array of strings representing plugin folder paths, deserialized from XML configuration.
PluginConfig
const string DataProPlugins = "dataProPlugins"
Constant key used to locate the base plugin configuration setting in app.config.string GetDataProPluginsSetting(string setting)
Concatenates the value of the"dataProPlugins"app setting (retrieved viaDataProConfig.GetAppSetting) with the providedsetting, separated by a dot (.). Used to construct full setting names for plugin-specific configuration.
PluginConfigSectionHandler
FilterHashKeyCollection HashKeys
Configuration property accessor for the"PluginFolders"element. Returns aFilterHashKeyCollectioncontainingFilterHashElementinstances parsed from the configuration section.
FilterHashKeyCollection
FilterHashElement this[int idx]
Indexer to accessFilterHashElementitems by zero-based index.protected override ConfigurationElement CreateNewElement()
Returns a newFilterHashElementinstance (used internally by .NET configuration system).protected override object GetElementKey(ConfigurationElement element)
Returns theKeyproperty of the givenFilterHashElement(used for internal collection management).
FilterHashElement
string Key
Required, key property (markedIsKey = true). Represents the identifier/name for the configuration entry.string Value
Optional property. Stores the associated value (e.g., a file path).
PluginManager
static T GetPlugin<T>() where T : class
Returns a single MEF-exported instance of typeT. Throws an exception (implicitly, via MEF) if zero or more than one export of typeTexists. Returnsnullif no export is found.static T GetPlugin<T>(string configPluginSetting) where T : class
Returns a specific MEF-exported instance of typeTby matchingitem.Value.ToString() == configPluginSetting. Returnsnullif no matching plugin is found.static IEnumerable<Lazy<T>> GetPlugins<T>() where T : class
Returns all MEF-exported instances of typeTasLazy<T>objects.List<Assembly> GetPluginList<T>() where T : class
Returns a deduplicated list ofAssemblyobjects from directories in the MEF catalog that contain at least one part (plugin). Note: This method returns after processing only the firstDirectoryCatalogin the catalog list; subsequent catalogs are ignored.static PluginManager GetPluginManager()
Thread-safe singleton accessor. Lazily initializes and returns the singlePluginManagerinstance.
3. Invariants
- Configuration Section Requirement: The
"DataPro.Core.PluginLib.Config"section must be present in the configuration file (DataPro.config). If absent,PluginManagerconstructor throws anException. - Plugin Directory Validation: Every
FilterHashElement.Value(interpreted as a plugin directory path) must point to an existing directory. If any directory does not exist,PluginManagerconstructor throws anIOException. - Thread Safety:
PluginManageris implemented as a singleton with lazy initialization protected by alockonThreadLock. All public static methods (GetPlugin,GetPlugins,GetPluginManager) are safe for concurrent use. - Assembly Loading Scope: Assemblies are loaded only from directories specified in the configuration section. No fallback to other paths occurs during initialization.
- MEF Composition Contract:
GetPlugin<T>()assumes exactly one export of typeTexists; otherwise, MEF behavior (exception ornull) applies.GetPlugin<T>(string)relies onToString()of the exported instance for selection—this is fragile and not type-safe.
4. Dependencies
This module depends on:
System.Configuration(forConfigurationSection,ConfigurationElement, etc.)System.ComponentModel.Composition(for MEF types:AggregateCatalog,CompositionContainer,DirectoryCatalog,Export,Lazy<T>)System.IO(forDirectoryInfo,FileInfo,Assembly.LoadFrom)System.Reflection(forAssembly,AssemblyName)DataPro.Core.Config(specificallyDataProConfig.GetSectionandDataProConfig.GetAppSetting)
This module is depended on by:
- Any component requiring plugin resolution (e.g., via
PluginManager.GetPlugin<T>()). - Configuration infrastructure that consumes
"DataPro.Core.PluginLib.Config"section.
5. Gotchas
GetPluginList<T>()is incomplete: It returns after processing only the firstDirectoryCataloginPluginCatalog.Catalogs, ignoring all subsequent plugin directories. This is likely a bug.GetPlugin<T>(string)usesToString()for selection: Matching plugins byitem.Value.ToString()is unreliable and not robust—plugins may not overrideToString()meaningfully, and this approach cannot distinguish between multiple instances of the same type.- Redundant assembly loading logic: The constructor contains a loop that loads assemblies manually (
Assembly.LoadFrom) after addingDirectoryCatalogto theAggregateCatalog. MEF’sDirectoryCatalogalready loads assemblies on-demand; this manual loading is unnecessary and may cause duplicate loads or version conflicts. - No error handling for assembly resolution: The
CurrentDomain_AssemblyResolveevent handler is defined but never subscribed toAppDomain.CurrentDomain.AssemblyResolve. Dependency resolution failures will not be handled. - Path handling comment is misleading: The commented-out
IsPathRootedcheck includes a typo ("absolete" instead of "absolute") and is disabled—no validation of path absoluteness occurs at runtime. PluginConfigDataunused in runtime logic: This class is defined but not referenced anywhere in the provided codebase. It appears to be a legacy or incomplete deserialization helper.- No cleanup/disposal:
PluginManagerholds unmanaged resources (CompositionContainer, catalogs, loaded assemblies). NoIDisposableimplementation or finalizer is present—potential memory leaks if the app domain is long-lived and plugins are reloaded.