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

5.9 KiB
Raw Permalink Blame History

source_files, generated_at, model, schema_version, sha256
source_files generated_at model schema_version sha256
Common/DTS.Common/ModuleCatalog/AggregateModuleCatalog.cs
2026-04-16T02:54:14.695851+00:00 Qwen/Qwen3-Coder-Next-FP8 1 7afb65b5d3f17781

ModuleCatalog

Purpose

The AggregateModuleCatalog class serves as a composite wrapper around multiple IModuleCatalog instances, enabling modular module discovery and management across heterogeneous sources (e.g., configuration files, assemblies, or dynamic catalogs) within the Prism-based module loading framework. It consolidates module definitions from its constituent catalogs into a unified interface while delegating core operations—such as dependency resolution, initialization, and module enumeration—to the underlying catalogs. Its primary role is to support extensibility by allowing additional catalogs to be added at runtime, while maintaining a single entry point for module catalog operations.


Public Interface

  • AggregateModuleCatalog()
    Constructor. Initializes a new instance with a default ModuleCatalog (stored as the first element in _catalogs). This default catalog is used for modules added via AddModule(ModuleInfo).

  • void AddCatalog(IModuleCatalog catalog)
    Appends a new IModuleCatalog instance to the internal list of catalogs. Throws ArgumentNullException if catalog is null.

  • IEnumerable<ModuleInfo> Modules { get; }
    Returns a flattened enumeration of all ModuleInfo instances across all contained catalogs, via SelectMany.

  • IEnumerable<ModuleInfo> GetDependentModules(ModuleInfo moduleInfo)
    Locates the single catalog containing moduleInfo (via Single(x => x.Modules.Contains(moduleInfo))) and delegates the call to that catalog. Returns the modules dependencies as reported by the underlying catalog.

  • IEnumerable<ModuleInfo> CompleteListWithDependencies(IEnumerable<ModuleInfo> modules)
    Groups the input modules by their source catalog (again using Single(...) to identify the catalog), then delegates CompleteListWithDependencies per catalog. Returns the union of all dependency-expanded module sets.

  • void Initialize()
    Invokes Initialize() on each catalog in _catalogs, enabling initialization logic (e.g., loading, validation) across all catalogs.

  • void AddModule(ModuleInfo moduleInfo)
    Adds moduleInfo exclusively to the first catalog in _catalogs (i.e., the default ModuleCatalog created in the constructor). Does not attempt to distribute modules across catalogs.


Invariants

  1. Catalog Membership Uniqueness:
    GetDependentModules and CompleteListWithDependencies assume exactly one catalog in _catalogs contains a given ModuleInfo. If a ModuleInfo appears in multiple catalogs, Single(...) will throw InvalidOperationException.
    This implies modules must be unique across all constituent catalogs.

  2. Default Catalog Preservation:
    The first catalog (_catalogs[0]) is always the initial ModuleCatalog instance created in the constructor. It is never removed or replaced.

  3. Module Addition Target:
    All modules added via AddModule(ModuleInfo) are placed in _catalogs[0]. Modules added via AddCatalog may reside in any catalog, but must not duplicate modules already in _catalogs[0] (to satisfy uniqueness).

  4. Catalog Initialization Order:
    Initialize() calls each catalogs Initialize() in the order they appear in _catalogs. No ordering guarantees beyond this sequence are specified.


Dependencies

  • Depends on:

    • Microsoft.Practices.Prism.Modularity (specifically, the IModuleCatalog and ModuleInfo types).
    • System, System.Collections.Generic, System.Linq (for LINQ operations like SelectMany, GroupBy, Single).
  • Depended on by:

    • Inferred from namespace (DTS.Common) and class name: likely consumed by Prism-based module initialization logic (e.g., ModuleManager or ModuleInitializer from Prism), though not explicit in the source.
    • No direct usage is visible in this file, but as an IModuleCatalog implementation, it is intended for integration with Prisms module loading pipeline.

Gotchas

  1. Fragile Catalog Lookup via Single(...):
    GetDependentModules and CompleteListWithDependencies use Single(x => x.Modules.Contains(moduleInfo)), which:

    • Fails if a ModuleInfo exists in multiple catalogs (throws InvalidOperationException).
    • Fails if a ModuleInfo is not found in any catalog (also throws InvalidOperationException).
      → This is a critical reliability risk if catalogs overlap or modules are added inconsistently.
  2. Asymmetric AddModule Behavior:
    AddModule only adds to the first catalog (_catalogs[0]). Users might expect modules to be distributed or added to a specific catalog, leading to confusion if they add modules expecting them to appear in a custom catalog added via AddCatalog.

  3. No Catalog Removal/Reordering Support:
    There is no method to remove catalogs or change their order. The first catalog is fixed, and subsequent catalogs are appended. This limits flexibility in dynamic scenarios.

  4. No Validation of Catalog Compatibility:
    The class does not enforce that catalogs use compatible ModuleInfo implementations or metadata schemas. Inconsistent catalogs may cause runtime errors during dependency resolution.

  5. No Thread Safety:
    The class is not marked thread-safe. Concurrent modifications (e.g., AddCatalog during enumeration) may cause exceptions.

  6. Assumes Modules.Contains Identity Semantics:
    Relies on IModuleCatalog.Modules.Contains(moduleInfo) to identify the source catalog. This assumes ModuleInfo implements value-based equality (e.g., via Equals/GetHashCode), which may not hold if ModuleInfo uses reference equality.