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

242 lines
10 KiB
Markdown

---
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.