Files

178 lines
12 KiB
Markdown
Raw Permalink Normal View History

2026-04-17 14:55:32 -04:00
---
source_files:
- DTS Viewer/DTS.Viewer/Settings.cs
- DTS Viewer/DTS.Viewer/ExportModule.cs
- DTS Viewer/DTS.Viewer/ViewerModule.cs
- DTS Viewer/DTS.Viewer/ViewerSession.cs
- DTS Viewer/DTS.Viewer/Bootstrapper.cs
generated_at: "2026-04-16T10:57:48.975205+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "f841428d718c70bf"
---
# DTS.Viewer Module Documentation
## 1. Purpose
The `DTS.Viewer` namespace provides the core module infrastructure for a Prism-based WPF viewer application. It implements a modular architecture using Unity dependency injection and Prism's modularity framework, enabling dynamic loading of viewer and export functionality. The module manages application bootstrapping, session lifecycle, plugin discovery, and region-based view composition. It serves as the entry point for initializing the viewer shell, registering view/viewmodel pairs, and coordinating module communication via event aggregation.
---
## 2. Public Interface
### Settings (DTS.Viewer.Properties)
```csharp
internal sealed partial class Settings
```
- **Settings()** - Constructor with optional event handler registration (currently commented out).
- **SettingChangingEventHandler(object sender, SettingChangingEventArgs e)** - Handles the `SettingChanging` event before a setting's value is changed. Currently empty implementation.
- **SettingsSavingEventHandler(object sender, CancelEventArgs e)** - Handles the `SettingsSaving` event before settings are saved. Currently empty implementation.
### ExportModule
```csharp
[Module(ModuleName = "Export")]
public class ExportModule : IExportModule
```
- **ExportModule(IUnityContainer unityContainer)** - Constructor accepting an injected Unity container.
- **SessionStarted** (property: `bool`) - Indicates whether a session has been started. Set to `true` after `StartSession()` completes.
- **Initialize()** - Registers `IExportModule` to `ExportModule` with container-controlled lifetime.
- **StartSession()** - Resolves `IEventAggregator`, publishes `LoadExportModuleEvent` with `LoadExportModuleArg`, sets `SessionStarted = true`.
- **RegisterTypes(IContainerRegistry containerRegistry)** - Calls `Initialize()`.
- **OnInitialized(IContainerProvider containerProvider)** - Empty implementation.
### ExportNameAttribute
```csharp
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
public class ExportNameAttribute : TextAttribute
```
- **ExportNameAttribute()** - Default constructor, sets `_assemblyName = "Export"`.
- **ExportNameAttribute(string s)** - Parameterized constructor, ignores parameter and sets `_assemblyName = "Export"`.
- **AssemblyName** (property: `string`) - Returns `_assemblyName` ("Export").
- **GetAttributeType()** - Returns `typeof(TextAttribute)`.
- **GetAssemblyName()** - Returns `AssemblyName`.
### ViewerModule
```csharp
[Module(ModuleName = "Viewer")]
public class ViewerModule : IViewerModule
```
- **ViewerModule(IUnityContainer unityContainer)** - Constructor accepting an injected Unity container.
- **SessionStarted** (property: `bool`) - Indicates whether a session has been started.
- **Initialize()** - Registers `IViewerModule` to `ViewerModule` with container-controlled lifetime.
- **StartSession()** - Resolves `IEventAggregator`, publishes `LoadViewModulEvent` with `LoadViewModulArg`, sets `SessionStarted = true`.
- **RegisterTypes(IContainerRegistry containerRegistry)** - Calls `Initialize()`.
- **OnInitialized(IContainerProvider containerProvider)** - Empty implementation.
### ViewerNameAttribute
```csharp
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
public class ViewerNameAttribute : TextAttribute
```
- **ViewerNameAttribute()** - Default constructor, sets `_assemblyName = "Viewer"`.
- **ViewerNameAttribute(string s)** - Parameterized constructor, ignores parameter and sets `_assemblyName = "Viewer"`.
- **AssemblyName** (property: `string`) - Returns `_assemblyName` ("Viewer").
- **GetAttributeType()** - Returns `typeof(TextAttribute)`.
- **GetAssemblyName()** - Returns `AssemblyName`.
### ViewerSession
```csharp
public class ViewerSession
```
- **Container** (property: `IUnityContainer`) - Gets the Unity container after `CreateSession()` is called.
- **_serviceLocator** (property: `IServiceLocator`) - Gets the service locator after `CreateSession()`.
- **_eventAggregator** (property: `IEventAggregator`) - Gets the event aggregator after `CreateSession()`.
- **_regionManager** (property: `IRegionManager`) - Gets the region manager after `CreateSession()`.
- **CustomConfigPath** (property: `string`) - Gets/sets custom configuration path for plugin loading.
- **ViewerSession()** - Empty constructor.
- **CreateSession(bool standalone, string customConfigPath = "")** - Creates the bootstrapper, initializes container/services, loads plugins via `PluginManager`, and publishes `AssemblyListNotificationViewer` event.
- **Terminate()** - Called during JMPS shutdown. Empty implementation.
### Bootstrapper
```csharp
public class Bootstrapper : UnityBootstrapper
```
- **Bootstrapper(bool standalone, string customConfigPath = "")** - Constructor accepting standalone mode flag and optional custom config path.
- **Standalone** (property: `bool`) - Gets/sets whether running in standalone mode.
- **CustomConfigPath** (property: `string`) - Gets/sets custom configuration path.
- **_ServiceLocator** (property: `IServiceLocator`) - Gets the service locator after `CreateShell()`.
- **_EventAggregator** (property: `IEventAggregator`) - Gets the event aggregator after `CreateShell()`.
- **ConfigureContainer()** - Registers `IViewerMainViewGrid` to `ViewerMainViewGrid` and `IViewerMainViewModel` to `ViewerMainViewModel` (singleton).
- **ConfigureRegionAdapterMappings()** - Registers region adapters for `Selector`, `ItemsControl`, `ContentControl`, and conditionally `StackPanel` (standalone only). Uses try/catch to ignore already-registered mappings.
- **CreateShell()** - Creates the main shell, resolves `IViewerMainViewModel`, registers regions, sets DataContext, and initializes the view model. Returns `DependencyObject` or `null` on exception.
- **CreateModuleCatalog()** - Returns resolved `IModuleCatalog` or new `AggregateModuleCatalog`.
- **ConfigureModuleCatalog()** - In standalone mode, reads plugin folders from config section `DTS.Common.Core.PluginLib.Config` under key `viewerPlugins`, creates `DirectoryModuleCatalog`.
- **InitializeModules()** - In standalone mode, registers `IDTSViewRegionManager` to `DTSViewRegionManager` (singleton), then calls base implementation.
---
## 3. Invariants
1. **Bootstrapper Singleton**: The `ViewerSession._bootstrapper` field should only be created once. The `CreateBootstrapper` method checks for null before creating a new instance.
2. **Session State Consistency**: Both `ExportModule.SessionStarted` and `ViewerModule.SessionStarted` are `false` by default and only set to `true` after `StartSession()` publishes its respective event.
3. **Module Registration Pattern**: Both `ExportModule` and `ViewerModule` register themselves as implementations of their respective interfaces using `ContainerControlledLifetimeManager` (singleton behavior within the container).
4. **Standalone Mode Behavior**:
- `ConfigureModuleCatalog()` only loads directory-based modules when `Standalone == true`.
- `InitializeModules()` only registers `IDTSViewRegionManager` when `Standalone == true`.
- `ConfigureRegionAdapterMappings()` only registers `StackPanel` adapter when `Standalone == true`.
5. **Attribute Constructor Behavior**: Both `ExportNameAttribute` and `ViewerNameAttribute` ignore their string parameter in the parameterized constructor, always returning hardcoded "Export" or "Viewer" respectively.
6. **Region Registration**: In `CreateShell()`, regions are only added if they don't already exist (`ContainsRegionWithName` check).
---
## 4. Dependencies
### External Dependencies (Imports)
| Namespace | Purpose |
|-----------|---------|
| `DTS.Common.Events` | Event types: `LoadExportModuleEvent`, `LoadViewModulEvent`, `AssemblyListNotificationViewer` |
| `DTS.Common.Interface` | Interfaces: `IExportModule`, `IViewerModule`, `IViewerMainViewGrid`, `IViewerMainViewModel`, `IShellViewModel`, `IDTSViewRegionManager` |
| `DTS.Common.Core.PluginLib` | `PluginManager`, `PluginConfigSectionHandler`, `FilterHashElement`, `AssemblyListInfo` |
| `DTS.Common.Base` | `TextAttribute` base class |
| `Prism.Events` / `Microsoft.Practices.Prism.Events` | `IEventAggregator`, event base classes |
| `Prism.Ioc` | `IContainerRegistry`, `IContainerProvider` |
| `Prism.Modularity` / `Microsoft.Practices.Prism.Modularity` | `IModule`, `IModuleCatalog`, `ModuleAttribute`, `AggregateModuleCatalog`, `DirectoryModuleCatalog` |
| `Prism.Regions` / `Microsoft.Practices.Prism.Regions` | `IRegionManager`, `Region`, `RegionAdapterMappings`, region adapters |
| `Unity` / `Microsoft.Practices.Unity` | `IUnityContainer`, `ContainerControlledLifetimeManager`, `InjectionMember` |
| `Microsoft.Practices.ServiceLocation` | `IServiceLocator`, `ServiceLocator` |
| `System.Configuration` | `ConfigurationManager`, configuration section handling |
| `System.ComponentModel.Composition.Hosting` | MEF composition support |
### Downstream Dependencies
The following types are registered by this module and expected to be consumed by other components:
- `IExportModule``ExportModule`
- `IViewerModule``ViewerModule`
- `IViewerMainViewGrid``ViewerMainViewGrid`
- `IViewerMainViewModel``ViewerMainViewModel`
- `IDTSViewRegionManager``DTSViewRegionManager`
---
## 5. Gotchas
1. **Ignored Constructor Parameter**: Both `ExportNameAttribute(string s)` and `ViewerNameAttribute(string s)` accept a string parameter but completely ignore it, always returning hardcoded values. This is misleading API design.
2. **Mixed Prism Namespace Versions**: The code imports from both legacy `Microsoft.Practices.Prism.*` namespaces and newer `Prism.*` namespaces. This suggests a migration in progress or dependency on both old and new Prism versions.
3. **Bootstrapper Memory Footprint**: The comment in `ViewerSession` 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 currently no mechanism to unload or recreate the bootstrapper.
4. **Empty Event Handlers**: `Settings.SettingChangingEventHandler` and `Settings.SettingsSavingEventHandler` have empty implementations with only placeholder comments.
5. **Silent Failures in Region Adapter Registration**: `ConfigureRegionAdapterMappings()` uses empty catch blocks (`try { ... } catch { }`) when registering region adapters, silently ignoring any registration failures.
6. **Exception Swallowing in CreateShell**: The `CreateShell()` method catches all exceptions, stores the message in a local variable `s` that is never used, and returns `null`. This makes debugging shell creation failures difficult.
7. **Commented-Out Code in ConfigureContainer**: There is significant commented-out code for conditional view registration based on `Standalone` mode, suggesting unfinished or experimental functionality.
8. **Redundant Null Check Pattern**: In `CreateBootstrapper`, the method checks `_bootstrapper == null` twice—once before the try block and once after, throwing an exception if still null. The inner catch already wraps and rethrows with context.
9. **Private Field Naming Convention**: Several fields use underscore prefix but are exposed via public properties with different names (e.g., `_customConfigPath` vs `CustomConfigPath`), while others like `_serviceLocator` have public getters but inconsistent naming.
10. **Module Self-Registration**: Both `ExportModule` and `ViewerModule` register themselves in `Initialize()`, which is called from `RegisterTypes()`. This is unusual—typically the container is configured before module initialization, not by the module itself.