Files

234 lines
12 KiB
Markdown
Raw Permalink Normal View History

2026-04-17 14:55:32 -04:00
---
source_files:
- Common/DTS.Common/Classes/UnityExtensions.cs
- Common/DTS.Common/Classes/StatusAndProgressBarEventArgs.cs
- Common/DTS.Common/Classes/Singleton.cs
- Common/DTS.Common/Classes/BulkObservableCollection.cs
- Common/DTS.Common/Classes/RegionNames.cs
- Common/DTS.Common/Classes/ImportData.cs
- Common/DTS.Common/Classes/ServiceCall.cs
- Common/DTS.Common/Classes/TagAwareBase.cs
- Common/DTS.Common/Classes/Utility.cs
- Common/DTS.Common/Classes/Tags.cs
generated_at: "2026-04-16T02:52:41.721329+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "b71265395aaf09cd"
---
# DTS.Common Classes Documentation
## 1. Purpose
This module provides foundational infrastructure utilities for the DTS application platform, focusing on dependency injection (via Unity), UI state management (status/progress), singleton pattern enforcement, high-performance collection operations, service orchestration, database-backed tagging system, and robust data access helpers. It serves as a shared library across the application to standardize common patterns, reduce boilerplate, and ensure thread-safe, consistent behavior for core operations like service queuing, tag management, and database interaction.
## 2. Public Interface
### `UnityExtensions`
- **`T TryResolve<T>(this IUnityContainer container) where T : class`**
Safely resolves a service of type `T` from the Unity container, returning `null` instead of throwing on failure.
### `StatusAndProgressBarEventArgs`
- **Properties**
- `StatusColor`: `Color` UI color for status indication.
- `StatusText`: `string` Human-readable status message.
- `ProgressValue`: `double` Numeric progress (e.g., 0.01.0 or 0100).
- `ProgressBarVisibility`: `Visibility` Controls whether the progress bar is visible.
- `Requester`: `IBaseViewModel` Originator of the status update.
- `ErrorText`: `string` Optional error message to display.
### `Singleton<T>`
- **`protected Singleton()`**
Constructor enforces singleton usage: throws `InvalidOperationException` if called directly (i.e., via `new T()` instead of `T.Instance`).
- **`public static T Instance`**
Gets the singleton instance. Throws the exception captured during static initialization if instance creation failed.
### `BulkObservableCollection<T>`
- **`void AddRange(IEnumerable<T> items)`**
Adds multiple items to the collection and fires a single `NotifyCollectionChangedAction.Reset` notification instead of per-item notifications. Logs exceptions via `APILogger`.
- **`void RemoveRange(IEnumerable<T> itemsToRemove)`**
Removes multiple items and fires a single `Reset` notification. Logs exceptions via `APILogger`.
### `RegionNames`
- **Constants**
Static string constants defining Prism region names used for UI composition (e.g., `"FrontRegion"`, `"MainRegion"`, `"ViewerGraphMainRegion"`, `"MenuRegion"`). No methods.
### `ImportData`
- **`enum ImportPageType`**
- `ImportSensor`, `ImportTestSetup`
- **`class SensorImportData`**
Holds parsed sensor import data:
- `GroupNameSensorListLookup`: `Dictionary<string, List<string>>`
- `SensorGroupNameLookup`, `SensorGroupTypeLookup`, `GroupNameTestObjectLookup`: `Dictionary<string, string>`
- `Errors`: `List<string>`
- `SensorISOCode`, `SensorISOChannelName`, `SensorUserCode`, `SensorUserChannelName`, `SensorDASSerialNumber`: `Dictionary<string, string>`
- `SensorChannelIndex`: `Dictionary<string, int>`
- **`class TestSetupImportData`**
Holds parsed test setup import data:
- `Name`, `Description`: `string`
- `SamplesPerSecond`, `PosttriggerSeconds`, `PretriggerSeconds`: `double`
- `RecordingMode`, `CalibrationBehavior`: Enum values
- `Version`: `int`
- `TestChannelOrders`, `Tags`: `List<string>`
- Clock configuration properties: `ClockMasterInput`, `ClockMasterOutput`, `ManageClocksOutsideOfDataPROMaster`, etc.
- `SampleRateForDAS`, `DomainIdForDAS`, `IsClockMaster`: `Dictionary<string, ...>`
### `ServiceCall`
- **`bool Started`**
Indicates whether the call has been started.
- **`Action WorkAction`**
The work to execute.
- **`void MarkDone()`**
Signals completion by calling `ServiceQueue.MarkFinished(this)`.
- **`string Name`**
Human-readable identifier.
- **`ServiceCall(string name)`**
Constructor.
### `ServiceQueue`
- **`static void Enqueue(ServiceCall call)`**
Adds a `ServiceCall` to the queue. Starts execution immediately if queue was empty.
- **`static void MarkFinished(ServiceCall call)`**
Removes the call from the queue and starts the next queued call if any. Handles non-active calls (not at head) by simple removal.
### `TagAwareBase`
- **`enum TagTypes`**
`User`, `Group`, `Template`, `TestSetup`, `Sensors`, `SensorModels`
- **`abstract TagTypes TagType { get; }`**
Must be implemented by derived classes to specify tag type.
- **`byte[] TagsBlobBytes`**
Gets/sets `TagIDs` as a byte array (for DB storage). Logs exceptions on failure.
- **`int[] TagIDs`**
Gets/sets the list of tag IDs.
- **`void SetTagsFromCommaSeparatedString(string tagText, Tags.GetSqlCommandDelegate getSqlCommand)`**
Parses comma-separated tags and sets `TagIDs`.
- **`virtual void SetTags(string[] tagsText, Tags.GetSqlCommandDelegate getSqlCommand)`**
Adds tags to DB and updates `TagIDs`. Raises `OnPropertyChanged("TagIDs")`.
- **`string GetTagsAsCommaSeparatedString(Tags.GetSqlCommandDelegate getSqlCommand)`**
Returns tags as comma-separated string.
- **`virtual string[] GetTagsArray(Tags.GetSqlCommandDelegate getSqlCommand)`**
Returns tag text array.
- **`virtual bool TagCompatible(string tags, ...)`**
Checks if any tag in the provided comma-separated string matches current tags.
- **`virtual bool TagCompatible(int[] tags)`**
Checks if any tag ID in `tags` intersects with `TagIDs`.
- **`virtual bool HasIntersectingTag(int[] tags)`**
Returns `true` if `tags` and `TagIDs` share any ID.
- **`void InsertTagsFromCommaSeparatedString(int id, TagTypes tagType, string tags, ...)`**
Sets tags and commits assignments.
- **`void Commit(int id, TagTypes tagType, ...)`**
Deletes existing tag assignments for the object, then inserts new assignments for `TagIDs`. Uses stored procedures `sp_TagAssignmentsDelete` and `sp_TagAssignmentsInsert`.
- **`List<int> GetTagIdList(int objectId, TagTypes tagType, ...)`**
Retrieves tag IDs for an object from DB via `sp_TagAssignmentsGet`. Logs failures.
### `Utility`
- **`static byte[] GetBytesFromStringArray(string[] array, string separator)`**
Joins array with `separator`, returns UTF-8 bytes.
- **`static string GetAllErrorMessages(Exception ex)`**
Recursively aggregates exception messages (including inner exceptions).
- **`static bool PingNetwork(string hostNameOrAddress)`**
Pings host with 4s timeout and fixed buffer. Returns `true` on success.
- **`static T GetX(IDataReader reader, string column, T defaultValue = default)`**
Generic pattern for safe column extraction:
- `GetUShort`, `GetUInt`, `GetString`, `GetStringArray`, `GetInt`, `GetDouble`, `GetShort`, `GetNullableDateTime`, `GetUlong`, `GetNullableInt`, `GetByteArray`, `GetBool`, `GetDateTime`, `GetLong`
All return `defaultValue` on `DBNull`, parse failure, or invalid column. Logs parse failures via `APILogger`.
### `Tags`
- **`class Tag`**
- `const int INVALID_ID = -1`
- `int ID`, `string Text`, `bool IsObsolete`
- Constructors: `(string, int)`, `(Tag)`, `(IDataRecord)`, `(DataRow)`
- `object Clone()``new Tag(this)`
- **`delegate SqlCommand GetSqlCommandDelegate(bool bNewConnection)`**
Factory for database commands.
- **`static Tags GetTagsInstance(GetSqlCommandDelegate getSqlCommand)`**
Gets singleton instance (lazy-initialized).
- **`static bool AddTag(string tagText, ...)`**
Adds tag to DB if not present. Returns `true` if added.
- **`static bool MigrateTag(string tagText, ...)`**
Commits tag (used for DB migration).
- **`static bool[] AddRange(string[] tagText, ...)`**
Adds multiple tags. Trims leading whitespace before adding.
- **`static int GetIDFromTagText(string tagText, ...)`**
Gets tag ID from DB (returns `Tag.INVALID_ID` if not found).
- **`static int[] GetIDsFromTagText(string[] tagText, ...)`**
Gets tag IDs for array of texts. Filters out `INVALID_ID`.
- **`static string GetTagTextFromID(int tagID, ...)`**
Gets tag text from memory cache (returns `null` if invalid/missing).
- **`static string[] GetTagTextFromIDs(int[] tagId, ...)`**
Gets tag texts from IDs. Filters invalid/whitespace.
- **`bool ContainsTag(string text)`**
Checks if tag exists in memory cache.
- **`void UpdateList(GetSqlCommandDelegate getSqlCommand)`**
Refreshes memory cache from DB via `sp_TagsGet`.
## 3. Invariants
- **Singleton<T>**:
- Only one instance per `T` exists. Attempting `new T()` throws `InvalidOperationException`.
- Static constructor exceptions are captured and rethrown on `Instance` access.
- **BulkObservableCollection<T>**:
- `AddRange`/`RemoveRange` fire exactly one `Reset` notification per call, regardless of item count.
- `CheckReentrancy()` is called before modifications to prevent reentrancy issues.
- **ServiceQueue**:
- Only one `ServiceCall` executes at a time (via `Task.Run`).
- Calls are processed in FIFO order.
- `MarkFinished` only advances the queue if the finished call is the head of the queue.
- **Tags**:
- Tags are immutable (no rename/delete/obsolete support).
- Memory cache (`_tagsLookup`) is lazily populated and updated only via `AddTag`, `MigrateTag`, or `UpdateList`.
- `Tag.INVALID_ID` (`-1`) is used to indicate missing tags.
- **TagAwareBase**:
- `TagIDs` is never `null` (defaults to `new int[0]`).
- `Commit` deletes existing assignments before inserting new ones.
## 4. Dependencies
- **Imports/References**:
- `Unity` (Microsoft Unity Container)
- `System.Windows` (`Color`, `Visibility`)
- `System.Data`, `System.Data.SqlClient` (ADO.NET)
- `DTS.Common.Base` (`BasePropertyChanged`, `IBaseViewModel`)
- `DTS.Common.Enums` (`RecordingModes`, `CalibrationBehaviors`, `InputClockSource`, `OutputClockSource`)
- `DTS.Common.Interface.Sensors` (`ISensor`)
- `DTS.Common.Utilities.Logging` (`APILogger`)
- **Depended upon by**:
- UI layers (via `RegionNames`, `StatusAndProgressBarEventArgs`)
- Data import modules (`ImportData`)
- Service orchestration consumers (`ServiceQueue`)
- Tag-aware entities (`TagAwareBase`)
- Database access layers (`Utility`, `Tags`)
## 5. Gotchas
- **`Singleton<T>`**:
- Static initialization exceptions are logged to `Console.WriteLine` (not `APILogger`).
- The singleton instance is created on first `Instance` access, not on module load.
- **`BulkObservableCollection<T>`**:
- `AddRange`/`RemoveRange` use `NotifyCollectionChangedAction.Reset`, which may cause UI controls to re-render entirely (not incremental updates).
- Exceptions in `AddRange`/`RemoveRange` are silently logged and do not propagate.
- **`ServiceQueue`**:
- `ServiceCall.Started` is used to prevent duplicate execution, but there is no cancellation mechanism.
- Non-active calls (not at head) are removed from the queue without execution.
- **`Tags`**:
- Memory cache (`_tagsLookup`) is *not* automatically updated after `AddTag`/`MigrateTag` (only updated on `UpdateList` or explicit `Commit`).
- `GetTagTextFromID` reads from cache only; if cache is stale, it may return `null` for valid IDs.
- **`TagAwareBase`**:
- `RemoveTags` is a stub (empty implementation).
- `SetTagsFromCommaSeparatedString` does *not* skip empty strings (despite commented-out null check referencing FogBugz #7176).
- **`Utility`**:
- `PingNetwork` uses a fixed 32-byte buffer and 4-second timeout.
- All `GetX` methods return `defaultValue` on parse failure without rethrowing.
- **`ImportData.TestSetupImportData`**:
- Clock master/slave properties (`ClockMasterInput`, `ClockMasterOutput`, etc.) default to `None` and `false`.