--- source_files: - DTS Viewer/DTS.Viewer.Reports/DTS.Viewer.PSDReport/PSDReportModule.cs - DTS Viewer/DTS.Viewer.Reports/DTS.Viewer.PSDReport/PSDReportSession.cs - DTS Viewer/DTS.Viewer.Reports/DTS.Viewer.PSDReport/Bootstrapper.cs generated_at: "2026-04-16T10:59:56.665208+00:00" model: "zai-org/GLM-5-FP8" schema_version: 1 sha256: "24a83d36ea7d74c2" --- # PSDReport Module Documentation ## 1. Purpose The `DTS.Viewer.PSDReport` module is a Prism-based plugin module for the DTS Viewer application that provides PSD (Power Spectral Density) report functionality. It implements the `IModule` interface for modular composition and can operate in both standalone and integrated modes. The module includes custom assembly attributes for metadata discovery, a session management system for bootstrapping Prism infrastructure, and a custom `UnityBootstrapper` for configuring dependency injection, region adapters, and dynamic module loading. --- ## 2. Public Interface ### PSDReportModule.cs **Class: `PSDReportModule`** ```csharp public PSDReportModule(IUnityContainer unityContainer) ``` Constructor accepting an `IUnityContainer` dependency injection. ```csharp public void Initialize() ``` Registers `IPSDReportModule` to `PSDReportModule` with `ContainerControlledLifetimeManager` (singleton lifetime). ```csharp public void StartSession() ``` Resolves `IEventAggregator`, publishes a `LoadViewModulEvent` with `LoadViewModulArg`, and sets `SessionStarted` to `true`. ```csharp public void RegisterTypes(IContainerRegistry containerRegistry) ``` Prism module lifecycle method; calls `Initialize()`. ```csharp public void OnInitialized(IContainerProvider containerProvider) ``` Prism module lifecycle method; currently empty implementation. **Property: `SessionStarted`** (read-only) ```csharp public bool SessionStarted { get; private set; } ``` Indicates whether `StartSession()` has been called. --- **Class: `PSDReportModuleNameAttribute`** (extends `TextAttribute`) ```csharp public PSDReportModuleNameAttribute() public PSDReportModuleNameAttribute(string s) ``` Assembly-level attribute returning `AssemblyNames.PSDReport.ToString()` for `AssemblyName`. ```csharp public override Type GetAttributeType() public override string GetAssemblyName() ``` --- **Class: `PSDReportModuleImageAttribute`** (extends `ImageAttribute`) ```csharp public PSDReportModuleImageAttribute() public PSDReportModuleImageAttribute(string s) ``` Assembly-level attribute providing image, name, group, and region metadata. ```csharp public override BitmapImage AssemblyImage { get; } public override string AssemblyName { get; } public override string AssemblyGroup { get; } // Returns eAssemblyGroups.Viewer.ToString() public override eAssemblyRegion AssemblyRegion { get; } // Returns eAssemblyRegion.PSDReportRegion ``` --- ### PSDReportSession.cs **Class: `PSDReportSession`** ```csharp public PSDReportSession() ``` Default (empty) constructor. ```csharp public void CreateSession(bool standalone, string customConfigPath = "") ``` Creates the bootstrapper, resolves container services (`IUnityContainer`, `IEventAggregator`, `IServiceLocator`, `IRegionManager`), loads plugins via `PluginManager`, and publishes the plugin list via `AssemblyListNotificationViewer` event. ```csharp public void Terminate() ``` Empty implementation; intended for shutdown scenarios. **Properties:** ```csharp public IUnityContainer Container { get; private set; } public IServiceLocator _serviceLocator { get; private set; } public IEventAggregator _eventAggregator { get; private set; } public IRegionManager _regionManager { get; private set; } public string CustomConfigPath { get; set; } ``` --- ### Bootstrapper.cs **Class: `Bootstrapper`** (extends `UnityBootstrapper`) ```csharp public Bootstrapper(bool standalone, string customConfigPath = "") ``` Constructor accepting standalone mode flag and optional custom config path. ```csharp protected override void ConfigureContainer() ``` Registers `IPSDReportMainViewGrid` to `PSDReportMainViewGrid` and `IPSDReportMainViewModel` to `PSDReportMainViewModel` (singleton). Calls `base.ConfigureContainer()`. ```csharp protected override RegionAdapterMappings ConfigureRegionAdapterMappings() ``` Registers region adapters for `Selector`, `ItemsControl`, `ContentControl`, and conditionally `StackPanel` (standalone mode only). Each registration is wrapped in try/catch to handle duplicate mappings. ```csharp protected override DependencyObject CreateShell() ``` Creates the shell by resolving `IPSDReportMainViewModel`, registering regions dynamically, setting DataContext, and initializing the view model. Returns `null` on exception. ```csharp protected override IModuleCatalog CreateModuleCatalog() ``` Returns resolved `IModuleCatalog` or creates new `AggregateModuleCatalog`. ```csharp protected override void ConfigureModuleCatalog() ``` For standalone mode only: reads plugin folder paths from configuration section `DTS.Common.Core.PluginLib.Config` and creates a `DirectoryModuleCatalog`. ```csharp protected override void InitializeModules() ``` For standalone mode only: registers `IDTSViewRegionManager` to `DTSViewRegionManager` (singleton) and calls `base.InitializeModules()`. **Properties:** ```csharp public bool Standalone { get; set; } public string CustomConfigPath { get; set; } public IServiceLocator _ServiceLocator { get; private set; } public IEventAggregator _EventAggregator { get; private set; } ``` --- ## 3. Invariants 1. **Singleton Registration**: `IPSDReportModule` is registered with `ContainerControlledLifetimeManager`, ensuring a single instance per container. 2. **Session State**: `SessionStarted` is `false` until `StartSession()` is called; it cannot be reset to `false` through the public interface. 3. **Bootstrapper Creation**: `CreateBootstrapper()` will not create a new bootstrapper if `_bootstrapper` is already non-null. 4. **Standalone Mode Behavior**: - `ConfigureModuleCatalog()` only adds directory catalog when `Standalone` is `true`. - `InitializeModules()` only registers `IDTSViewRegionManager` when `Standalone` is `true`. - `StackPanel` region adapter is only registered when `Standalone` is `true`. 5. **Region Registration**: In `CreateShell()`, regions are only added if they don't already exist (`ContainsRegionWithName` check). 6. **Assembly Attributes**: Both `PSDReportModuleNameAttribute` and `PSDReportModuleImageAttribute` are decorated with `AllowMultiple = false`. --- ## 4. Dependencies ### This module depends on: **Prism Framework:** - `Prism.Ioc` - `IContainerRegistry`, `IContainerProvider` - `Prism.Modularity` - `IModule`, `ModuleAttribute`, `IModuleCatalog` - `Prism.Events` - `IEventAggregator` - `Microsoft.Practices.Prism.Events` - `IEventAggregator` (legacy) - `Microsoft.Practices.Prism.Modularity` - `IModuleCatalog`, `UnityBootstrapper` - `Microsoft.Practices.Prism.Regions` - `IRegionManager`, `RegionAdapterMappings`, `Region`, `RegionManager` - `Microsoft.Practices.Prism.UnityExtensions` - `UnityBootstrapper` **Unity DI:** - `Unity` - `IUnityContainer` - `Unity.Lifetime` - `ContainerControlledLifetimeManager` - `Microsoft.Practices.Unity` - `IUnityContainer`, `InjectionMember` **DTS Common Libraries:** - `DTS.Common` - `AssemblyNames`, `AssemblyInfo`, `eAssemblyGroups`, `eAssemblyRegion` - `DTS.Common.Events` - `LoadViewModulEvent`, `LoadViewModulArg`, `AssemblyListNotificationViewer`, `AssemblyListInfo` - `DTS.Common.Interface` - `IPSDReportModule`, `IPSDReportMainViewGrid`, `IPSDReportMainViewModel`, `IShellViewModel`, `IDTSViewRegionManager` - `DTS.Common.Base` - `TextAttribute`, `ImageAttribute` - `DTS.Common.Core.PluginLib` - `PluginManager`, `PluginConfigSectionHandler`, `FilterHashElement`, `DTSViewRegionManager` **WPF/.NET:** - `System.Windows` - `DependencyObject`, `DependencyProperty` - `System.Windows.Controls` - `ItemsControl`, `ContentControl`, `StackPanel` - `System.Windows.Media.Imaging` - `BitmapImage` - `System.Configuration` - `ConfigurationManager` - `System.ComponentModel.Composition.Hosting` - (imported but not directly used in visible code) ### What depends on this module: Not determinable from source alone. The module publishes `LoadViewModulEvent` and `AssemblyListNotificationViewer` events, suggesting other components subscribe to these events. --- ## 5. Gotchas 1. **Dual EventAggregator Imports**: The code imports `IEventAggregator` from both `Prism.Events` (modern) and `Microsoft.Practices.Prism.Events` (legacy). `PSDReportModule` uses the modern namespace while `PSDReportSession` uses the legacy namespace. This could cause runtime issues if they resolve to different instances. 2. **Empty Constructor Comment**: `PSDReportSession` has a comment `// ReSharper disable EmptyConstructor` suggesting the empty constructor may be intentional but non-obvious. 3. **Bootstrapper Memory Footprint**: The comment in `PSDReportSession` notes: *"It appears that the current bootstrapper loads around 40 MB into memory. To completely unload the bootstrapper would take same research and effort."* There is no mechanism to unload or recreate the bootstrapper. 4. **Silent Failure in CreateShell**: `CreateShell()` catches all exceptions, stores the message in a local variable `s` that is never used, and returns `null`. This silently swallows errors. 5. **Region Adapter Registration Swallows Errors**: `ConfigureRegionAdapterMappings()` wraps each registration in try/catch with empty catch blocks, silently ignoring duplicate mapping exceptions. 6. **Commented-Out Code in ConfigureContainer**: There is commented-out code for conditional registration based on `Standalone` mode, suggesting the registration strategy changed but the old code was preserved. 7. **TODO Comment**: `PSDReportSession.CreateSession()` contains `//TODO: review publishPlugins vs base.InitializeModules();` indicating incomplete design review. 8. **Inconsistent Naming Convention**: Some private fields use underscore prefix (`_unityContainer`, `_eventAggregator`) while others don't (`Container`). Public properties mix conventions (`_serviceLocator` is public with underscore prefix). 9. **Unused Imports**: `System.Runtime.InteropServices.ComTypes` is imported in `Bootstrapper.cs` but the `IStream` type is not used. 10. **Module Self-Registration**: `PSDReportModule.Initialize()` registers its own type (`IPSDReportModule` → `PSDReportModule`), which is unusual since the module instance already exists when `Initialize()` is called.