Files
2026-04-17 14:55:32 -04:00

7.5 KiB

source_files, generated_at, model, schema_version, sha256
source_files generated_at model schema_version sha256
Common/DTS.Common.Core/PluginLib/PluginConfigData.cs
Common/DTS.Common.Core/PluginLib/PluginConfig.cs
Common/DTS.Common.Core/PluginLib/PluginConfigSectionHandler.cs
Common/DTS.Common.Core/PluginLib/PluginManager.cs
2026-04-16T11:42:06.536831+00:00 zai-org/GLM-5-FP8 1 698a84042cfeb418

PluginLib Module Documentation

1. Purpose

The PluginLib module provides a Managed Extensibility Framework (MEF)-based plugin infrastructure for the DTS system. It handles discovery, loading, and retrieval of plugins from configurable directories, supporting both single-plugin resolution and multiple implementations of the same interface. The module abstracts configuration management through custom configuration section handlers and provides thread-safe singleton access to the plugin catalog and container.


2. Public Interface

PluginManager (Class)

The primary entry point for plugin operations.

Method Signature Description
GetPluginManager public static PluginManager GetPluginManager(string appPath) Returns the singleton instance of PluginManager. Initializes the plugin system on first call with the provided appPath. Thread-safe via lock on THREAD_LOCK.
GetPlugin<T> public static T GetPlugin<T>() where T : class Retrieves a single MEF export of type T. Returns null if no export exists. Throws if multiple exports exist for the same type.
GetPlugin<T> public static T GetPlugin<T>(string configPluginSetting) where T : class Retrieves a specific plugin from multiple exports by matching configPluginSetting against the plugin's ToString() value.
GetPlugins<T> public static IEnumerable<Lazy<T>> GetPlugins<T>() where T : class Returns all MEF exports of type T as lazy-initialized references.
GetPluginList<T> public List<Assembly> GetPluginList<T>() where T : class Returns a list of distinct Assembly objects from all loaded directory catalogs. Note: The generic type parameter T is not used in the implementation.
Property Type Description
PluginCatalog AggregateCatalog The MEF aggregate catalog containing all loaded plugin directories.

PluginConfig (Static Class)

Provides configuration helper methods.

Member Signature Description
DTSPlugins public const string DTSPlugins = "DTSPlugins" Constant for the app setting key name.
GetDTSPluginsSetting public static string GetDTSPluginsSetting(string setting) Concatenates the app setting value for DTSPlugins with the provided setting parameter using . as separator.

PluginConfigSectionHandler (Class)

Configuration section handler for DTS.Common.Core.PluginLib.Config.

Property Type Description
HashKeys FilterHashKeyCollection Returns the collection of plugin folder elements from the configuration section.

FilterHashKeyCollection (Class)

Collection class for configuration elements.

Member Signature Description
this[int idx] public FilterHashElement this[int idx] Indexer to access elements by position.

FilterHashElement (Class)

Represents a single plugin folder configuration entry.

Property Type Required Description
Key string Yes The key identifier for the element.
Value string No The plugin directory path.

PluginConfigData (Class)

XML serialization support class for legacy configuration format.

Field Type Description
PluginFolders string[] Array of plugin folder paths. Serialized with XmlArrayItem("Folder") attribute.

3. Invariants

  1. Singleton Pattern: _pluginManager is a static singleton; once initialized, subsequent calls to GetPluginManager return the existing instance regardless of the appPath parameter passed.

  2. Thread Safety: All access to the singleton initialization is protected by THREAD_LOCK object.

  3. Configuration Requirement: The configuration section "DTS.Common.Core.PluginLib.Config" must exist in the application configuration file, or the PluginManager constructor throws an Exception.

  4. Directory Existence: All plugin directories specified in FilterHashElement.Value must exist at initialization time, or an IOException is thrown.

  5. Assembly Exclusion: Assemblies with names starting with "DTS.Common", "C1", or "Xceed" are explicitly excluded from manual assembly loading in the constructor.

  6. MEF Export Uniqueness: GetPlugin<T>() (the parameterless overload) expects exactly zero or one export of type T; MEF throws an exception if multiple exports exist.


4. Dependencies

This module depends on:

  • DTS.Common.Core.Config - For DTSConfig.GetSection(), DTSConfig.GetAppSetting(), and DTSConfig.DTSConfigInit()
  • DTS.Common.Utilities.Logging - For APILogger.Log() static method
  • System.ComponentModel.Composition.Hosting - MEF container and catalog types
  • System.ComponentModel.Composition.ReflectionModel - For ReflectionModelServices.GetPartType()
  • System.Configuration - For configuration section infrastructure
  • System.Xml.Serialization - For PluginConfigData XML serialization

Consumers:

  • Any module requiring plugin extensibility via MEF exports
  • Code calling PluginManager.GetPlugin<T>() or PluginManager.GetPlugins<T>()

5. Gotchas

  1. Unused Assembly Resolve Handler: The method CurrentDomain_AssemblyResolve is defined but never wired up to AppDomain.CurrentDomain.AssemblyResolve. It will never be called unless external code attaches it.

  2. Configuration Section Name Inconsistency: PluginConfigData is decorated with [XmlRoot(ElementName = "DatPro.Core.PluginLib.Config")] (legacy "DatPro" naming), while PluginManager looks for "DTS.Common.Core.PluginLib.Config". These are different section names; PluginConfigData appears to be legacy/unused code.

  3. Unused Parameter in GetPluginList: The generic type parameter T in GetPluginList<T>() is declared but never used in the method body. The method returns all assemblies regardless of type.

  4. Dead Code Before Lock: In GetPluginManager(), a DirectoryInfo object is created from appPath before the lock but never used:

    if (!string.IsNullOrWhiteSpace(appPath))
    {
        var directoryInfo = new DirectoryInfo(appPath);
    }
    
  5. Empty Loop Bodies: The singleton check contains loops with empty bodies:

    foreach (var catalog in _pluginManager.PluginCatalog.Catalogs)
    {
        var directoryCatalog = catalog as DirectoryCatalog;
        if (directoryCatalog == null) continue;
    }
    

    This appears to be vestigial code with no effect.

  6. Plugin Matching via ToString(): GetPlugin<T>(string configPluginSetting) matches plugins by comparing item.Value.ToString() to configPluginSetting. This relies on the plugin's ToString() override returning a meaningful identifier.

  7. Null Return Possible: GetPlugin<T>() returns null if no export is found, not an exception. Callers must handle null.

  8. Hardcoded Assembly Exclusions: The exclusion list ("DTS.Common", "C1", "Xceed") is hardcoded in the constructor and not configurable.