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