docs+ui: backfill XML doc comments and finish dashboard layout pass

Adds missing <summary>/<param> XML docs across 99 server, worker, and test
files so CommentChecker reports zero issues (TreatWarningsAsErrors needs the
analyzer clean). Bundles in WIP dashboard work: NavSection extraction,
MainLayout/site.css/js styling alignment, and DashboardOptions/Auth tweaks.
This commit is contained in:
Joseph Doherty
2026-05-27 14:20:10 -04:00
parent 382861c602
commit 615b487a77
110 changed files with 1473 additions and 192 deletions
@@ -41,12 +41,16 @@ public sealed class AlarmCommandHandler : IAlarmCommandHandler
private AlarmDispatcher? dispatcher;
private bool disposed;
/// <summary>Initializes a new alarm command handler with the given event queue.</summary>
/// <param name="eventQueue">The event queue.</param>
public AlarmCommandHandler(MxAccessEventQueue eventQueue)
: this(eventQueue, () => new WnWrapAlarmConsumer(), threadAffinityCheck: null)
{
}
/// <summary>Test seam — inject a custom consumer factory.</summary>
/// <param name="eventQueue">The event queue.</param>
/// <param name="consumerFactory">The alarm consumer factory.</param>
public AlarmCommandHandler(
MxAccessEventQueue eventQueue,
Func<IMxAccessAlarmConsumer> consumerFactory)
@@ -68,6 +72,9 @@ public sealed class AlarmCommandHandler : IAlarmCommandHandler
/// optional: tests that already drive the handler on a single
/// thread can pass <c>null</c>.
/// </summary>
/// <param name="eventQueue">The event queue.</param>
/// <param name="consumerFactory">The alarm consumer factory.</param>
/// <param name="threadAffinityCheck">Optional thread affinity check action.</param>
public AlarmCommandHandler(
MxAccessEventQueue eventQueue,
Func<IMxAccessAlarmConsumer> consumerFactory,
@@ -78,6 +85,7 @@ public sealed class AlarmCommandHandler : IAlarmCommandHandler
this.threadAffinityCheck = threadAffinityCheck;
}
/// <summary>Gets a value indicating whether the handler is subscribed.</summary>
public bool IsSubscribed
{
get { lock (syncRoot) return dispatcher is not null; }
@@ -38,6 +38,10 @@ public sealed class AlarmDispatcher : IDisposable
private readonly EventHandler<MxAlarmTransitionEvent> handler;
private bool disposed;
/// <summary>Initializes a new alarm dispatcher for the given consumer, sink, and session ID.</summary>
/// <param name="consumer">The alarm consumer.</param>
/// <param name="sink">The alarm event sink.</param>
/// <param name="sessionId">The session identifier.</param>
public AlarmDispatcher(
IMxAccessAlarmConsumer consumer,
MxAccessAlarmEventSink sink,
@@ -61,6 +65,7 @@ public sealed class AlarmDispatcher : IDisposable
/// transitions. The supplied subscription expression follows the
/// canonical <c>\\&lt;machine&gt;\Galaxy!&lt;area&gt;</c> format.
/// </summary>
/// <param name="subscription">The subscription expression (e.g., <c>\\HOST\Galaxy!Area</c>).</param>
public void Subscribe(string subscription)
{
if (disposed) throw new ObjectDisposedException(nameof(AlarmDispatcher));
@@ -72,6 +77,13 @@ public sealed class AlarmDispatcher : IDisposable
/// consumer's <c>AlarmAckByGUID</c>. Returns the AVEVA-native
/// status code (0 = success).
/// </summary>
/// <param name="alarmGuid">The alarm GUID.</param>
/// <param name="ackComment">The acknowledgment comment.</param>
/// <param name="ackOperatorName">The operator name.</param>
/// <param name="ackOperatorNode">The operator node.</param>
/// <param name="ackOperatorDomain">The operator domain.</param>
/// <param name="ackOperatorFullName">The operator full name.</param>
/// <returns>The AVEVA-native status code.</returns>
public int Acknowledge(
Guid alarmGuid,
string ackComment,
@@ -95,6 +107,15 @@ public sealed class AlarmDispatcher : IDisposable
/// Routes to the consumer's <c>AcknowledgeByName</c> path which
/// maps to <c>wwAlarmConsumerClass.AlarmAckByName</c>.
/// </summary>
/// <param name="alarmName">The alarm name.</param>
/// <param name="providerName">The provider name.</param>
/// <param name="groupName">The group name.</param>
/// <param name="ackComment">The acknowledgment comment.</param>
/// <param name="ackOperatorName">The operator name.</param>
/// <param name="ackOperatorNode">The operator node.</param>
/// <param name="ackOperatorDomain">The operator domain.</param>
/// <param name="ackOperatorFullName">The operator full name.</param>
/// <returns>The AVEVA-native status code.</returns>
public int AcknowledgeByName(
string alarmName,
string providerName,
@@ -213,8 +234,10 @@ public sealed class AlarmDispatcher : IDisposable
};
}
/// <summary>Gets the session ID.</summary>
public string SessionId => sessionId;
/// <inheritdoc />
public void Dispose()
{
if (disposed) return;
@@ -23,6 +23,7 @@ public static class AlarmRecordTransitionMapper
/// <see cref="MxAlarmStateKind"/>. Unknown values map to
/// <see cref="MxAlarmStateKind.Unspecified"/>.
/// </summary>
/// <param name="stateXml">The state XML string from AVEVA (e.g., UNACK_ALM, ACK_RTN).</param>
public static MxAlarmStateKind ParseStateKind(string? stateXml)
{
if (string.IsNullOrWhiteSpace(stateXml)) return MxAlarmStateKind.Unspecified;
@@ -48,6 +49,8 @@ public static class AlarmRecordTransitionMapper
/// <item><description>Anything else → Unspecified (no proto kind to emit).</description></item>
/// </list>
/// </summary>
/// <param name="previous">The previous alarm state kind.</param>
/// <param name="current">The current alarm state kind.</param>
public static AlarmTransitionKind MapTransition(
MxAlarmStateKind previous,
MxAlarmStateKind current)
@@ -81,6 +84,9 @@ public static class AlarmRecordTransitionMapper
/// AcknowledgeAlarm RPC echoing a reference back as a GUID lookup)
/// don't need translation.
/// </summary>
/// <param name="providerName">The provider name, or null.</param>
/// <param name="groupName">The group name, or null.</param>
/// <param name="alarmName">The alarm name, or null.</param>
public static string ComposeFullReference(string? providerName, string? groupName, string? alarmName)
{
string provider = providerName ?? string.Empty;
@@ -14,12 +14,20 @@ namespace ZB.MOM.WW.MxGateway.Worker.MxAccess;
public interface IAlarmCommandHandler : IDisposable
{
/// <summary>Begin a subscription against the supplied AVEVA alarm-provider expression.</summary>
/// <param name="subscription">The AVEVA alarm-provider subscription expression.</param>
/// <param name="sessionId">The session identifier.</param>
void Subscribe(string subscription, string sessionId);
/// <summary>Tear down the active subscription. No-op if not subscribed.</summary>
void Unsubscribe();
/// <summary>Acknowledge a single alarm by GUID. Returns AVEVA's native status (0 = success).</summary>
/// <param name="alarmGuid">The alarm GUID.</param>
/// <param name="comment">The acknowledgment comment.</param>
/// <param name="operatorUser">The operator user name.</param>
/// <param name="operatorNode">The operator node name.</param>
/// <param name="operatorDomain">The operator domain name.</param>
/// <param name="operatorFullName">The operator full name.</param>
int Acknowledge(
Guid alarmGuid,
string comment,
@@ -32,6 +40,14 @@ public interface IAlarmCommandHandler : IDisposable
/// Acknowledge a single alarm by (name, provider, group) — used when
/// the caller has the human-readable reference but not the GUID.
/// </summary>
/// <param name="alarmName">The alarm name.</param>
/// <param name="providerName">The provider name.</param>
/// <param name="groupName">The group name.</param>
/// <param name="comment">The acknowledgment comment.</param>
/// <param name="operatorUser">The operator user name.</param>
/// <param name="operatorNode">The operator node name.</param>
/// <param name="operatorDomain">The operator domain name.</param>
/// <param name="operatorFullName">The operator full name.</param>
int AcknowledgeByName(
string alarmName,
string providerName,
@@ -46,6 +62,7 @@ public interface IAlarmCommandHandler : IDisposable
/// Snapshot the currently-active alarm set, optionally scoped to a
/// prefix matched against <c>AlarmFullReference</c>.
/// </summary>
/// <param name="alarmFilterPrefix">Optional prefix to filter alarms by.</param>
IReadOnlyList<ActiveAlarmSnapshot> QueryActive(string? alarmFilterPrefix);
/// <summary>
@@ -45,6 +45,7 @@ public interface IMxAccessAlarmConsumer : IDisposable
/// name). Subscribe does not start any polling of its own; the caller
/// drives polls explicitly via <see cref="PollOnce"/>.
/// </summary>
/// <param name="subscription">The subscription expression (e.g., <c>\\HOST\Galaxy!Area</c>).</param>
void Subscribe(string subscription);
/// <summary>
@@ -53,6 +54,13 @@ public interface IMxAccessAlarmConsumer : IDisposable
/// user / node / domain / full-name and the comment land atomically
/// with the ack transition in the alarm-history log.
/// </summary>
/// <param name="alarmGuid">The alarm GUID.</param>
/// <param name="ackComment">The acknowledgment comment.</param>
/// <param name="ackOperatorName">The operator name.</param>
/// <param name="ackOperatorNode">The operator node.</param>
/// <param name="ackOperatorDomain">The operator domain.</param>
/// <param name="ackOperatorFullName">The operator full name.</param>
/// <returns>The AVEVA-native status code.</returns>
int AcknowledgeByGuid(
Guid alarmGuid,
string ackComment,
@@ -68,6 +76,15 @@ public interface IMxAccessAlarmConsumer : IDisposable
/// <see cref="AcknowledgeByGuid"/>, used when the caller has the
/// human-readable reference but not the canonical GUID.
/// </summary>
/// <param name="alarmName">The alarm name.</param>
/// <param name="providerName">The provider name.</param>
/// <param name="groupName">The group name.</param>
/// <param name="ackComment">The acknowledgment comment.</param>
/// <param name="ackOperatorName">The operator name.</param>
/// <param name="ackOperatorNode">The operator node.</param>
/// <param name="ackOperatorDomain">The operator domain.</param>
/// <param name="ackOperatorFullName">The operator full name.</param>
/// <returns>The AVEVA-native status code.</returns>
int AcknowledgeByName(
string alarmName,
string providerName,
@@ -30,11 +30,15 @@ public sealed class MxAccessAlarmEventSink : IMxAccessEventSink
private string sessionId = string.Empty;
private bool attached;
/// <summary>Initializes a new instance of the MxAccessAlarmEventSink class with default dependencies.</summary>
public MxAccessAlarmEventSink()
: this(new MxAccessEventQueue(), new MxAccessEventMapper())
{
}
/// <summary>Initializes a new instance of the MxAccessAlarmEventSink class.</summary>
/// <param name="eventQueue">Queue for buffering converted alarm events.</param>
/// <param name="eventMapper">Converter for alarm transitions to protobuf format.</param>
public MxAccessAlarmEventSink(
MxAccessEventQueue eventQueue,
MxAccessEventMapper eventMapper)
@@ -71,6 +75,17 @@ public sealed class MxAccessAlarmEventSink : IMxAccessEventSink
/// tests can drive the proto build path without a real COM event
/// source.
/// </summary>
/// <param name="alarmFullReference">The fully qualified alarm object reference.</param>
/// <param name="sourceObjectReference">The object that sourced the alarm.</param>
/// <param name="alarmTypeName">The alarm type name.</param>
/// <param name="transitionKind">The kind of alarm transition.</param>
/// <param name="severity">The alarm severity level.</param>
/// <param name="originalRaiseTimestampUtc">The original alarm raise timestamp in UTC, if available.</param>
/// <param name="transitionTimestampUtc">The timestamp of this transition in UTC.</param>
/// <param name="operatorUser">The user who performed the operation, if applicable.</param>
/// <param name="operatorComment">The operator's comment, if any.</param>
/// <param name="category">The alarm category.</param>
/// <param name="description">The alarm description.</param>
internal void EnqueueTransition(
string alarmFullReference,
string sourceObjectReference,
@@ -98,6 +98,12 @@ public sealed class MxAccessBaseEventSink : IMxAccessEventSink
/// Exposed <c>internal</c> so unit tests can drive the integrated
/// sink → mapper → queue path without a live MXAccess COM event source.
/// </summary>
/// <param name="hLMXServerHandle">The MXAccess server handle.</param>
/// <param name="phItemHandle">The MXAccess item handle.</param>
/// <param name="pvItemValue">The new item value.</param>
/// <param name="pwItemQuality">The item quality.</param>
/// <param name="pftItemTimeStamp">The item timestamp.</param>
/// <param name="pVars">Status array from MXAccess event.</param>
internal void OnDataChange(
int hLMXServerHandle,
int phItemHandle,
@@ -128,6 +134,9 @@ public sealed class MxAccessBaseEventSink : IMxAccessEventSink
/// Handles the MXAccess <c>OnWriteComplete</c> COM event. Exposed
/// <c>internal</c> as a unit-test seam; see <see cref="OnDataChange"/>.
/// </summary>
/// <param name="hLMXServerHandle">The MXAccess server handle.</param>
/// <param name="phItemHandle">The MXAccess item handle.</param>
/// <param name="pVars">Status array from MXAccess event.</param>
internal void OnWriteComplete(
int hLMXServerHandle,
int phItemHandle,
@@ -145,6 +154,9 @@ public sealed class MxAccessBaseEventSink : IMxAccessEventSink
/// Handles the MXAccess <c>OperationComplete</c> COM event. Exposed
/// <c>internal</c> as a unit-test seam; see <see cref="OnDataChange"/>.
/// </summary>
/// <param name="hLMXServerHandle">The MXAccess server handle.</param>
/// <param name="phItemHandle">The MXAccess item handle.</param>
/// <param name="pVars">Status array from MXAccess event.</param>
internal void OperationComplete(
int hLMXServerHandle,
int phItemHandle,
@@ -162,6 +174,13 @@ public sealed class MxAccessBaseEventSink : IMxAccessEventSink
/// Handles the MXAccess <c>OnBufferedDataChange</c> COM event. Exposed
/// <c>internal</c> as a unit-test seam; see <see cref="OnDataChange"/>.
/// </summary>
/// <param name="hLMXServerHandle">The MXAccess server handle.</param>
/// <param name="phItemHandle">The MXAccess item handle.</param>
/// <param name="dtDataType">The data type of the buffered value.</param>
/// <param name="pvItemValue">The new item value.</param>
/// <param name="pwItemQuality">The item quality.</param>
/// <param name="pftItemTimeStamp">The item timestamp.</param>
/// <param name="pVars">Status array from MXAccess event.</param>
internal void OnBufferedDataChange(
int hLMXServerHandle,
int phItemHandle,
@@ -46,6 +46,9 @@ public sealed class MxAccessCommandExecutor : IStaCommandExecutor
/// optional — when null, alarm-side commands return an
/// "alarm consumer not configured" diagnostic.
/// </summary>
/// <param name="session">MXAccess session on the STA thread.</param>
/// <param name="variantConverter">Converter for MXAccess variant values to MxValue protobuf messages.</param>
/// <param name="alarmCommandHandler">Optional handler for alarm-side commands.</param>
public MxAccessCommandExecutor(
MxAccessSession session,
VariantConverter variantConverter,
@@ -63,6 +66,10 @@ public sealed class MxAccessCommandExecutor : IStaCommandExecutor
/// ReadBulk is exercised against a fake worker that pre-populates the
/// value cache — the executor falls back to a no-op pump step.
/// </summary>
/// <param name="session">MXAccess session on the STA thread.</param>
/// <param name="variantConverter">Converter for MXAccess variant values to MxValue protobuf messages.</param>
/// <param name="alarmCommandHandler">Optional handler for alarm-side commands.</param>
/// <param name="pumpStep">Action to pump Windows messages, or null for tests.</param>
public MxAccessCommandExecutor(
MxAccessSession session,
VariantConverter variantConverter,
@@ -593,6 +593,9 @@ public sealed class MxAccessSession : IDisposable
/// captured as <see cref="BulkWriteResult"/> entries with
/// <c>was_successful = false</c>; the loop never throws.
/// </summary>
/// <param name="serverHandle">The MXAccess server handle.</param>
/// <param name="entries">The write entries to process.</param>
/// <param name="convertValue">Converts protobuf MxValue to COM-compatible variant.</param>
public IReadOnlyList<BulkWriteResult> WriteBulk(
int serverHandle,
IReadOnlyList<WriteBulkEntry> entries,
@@ -622,6 +625,9 @@ public sealed class MxAccessSession : IDisposable
}
/// <summary>Bulk Write2 — sequential MXAccess <see cref="Write2"/> per entry.</summary>
/// <param name="serverHandle">The MXAccess server handle.</param>
/// <param name="entries">The write2 entries to process.</param>
/// <param name="convertValue">Converts protobuf MxValue to COM-compatible variant.</param>
public IReadOnlyList<BulkWriteResult> Write2Bulk(
int serverHandle,
IReadOnlyList<Write2BulkEntry> entries,
@@ -656,6 +662,9 @@ public sealed class MxAccessSession : IDisposable
}
/// <summary>Bulk WriteSecured — sequential MXAccess <see cref="WriteSecured"/> per entry.</summary>
/// <param name="serverHandle">The MXAccess server handle.</param>
/// <param name="entries">The WriteSecured entries to process.</param>
/// <param name="convertValue">Converts protobuf MxValue to COM-compatible variant.</param>
public IReadOnlyList<BulkWriteResult> WriteSecuredBulk(
int serverHandle,
IReadOnlyList<WriteSecuredBulkEntry> entries,
@@ -690,6 +699,9 @@ public sealed class MxAccessSession : IDisposable
}
/// <summary>Bulk WriteSecured2 — sequential MXAccess <see cref="WriteSecured2"/> per entry.</summary>
/// <param name="serverHandle">The MXAccess server handle.</param>
/// <param name="entries">The WriteSecured2 entries to process.</param>
/// <param name="convertValue">Converts protobuf MxValue to COM-compatible variant.</param>
public IReadOnlyList<BulkWriteResult> WriteSecured2Bulk(
int serverHandle,
IReadOnlyList<WriteSecured2BulkEntry> entries,
@@ -734,6 +746,10 @@ public sealed class MxAccessSession : IDisposable
/// iteration so the worker's STA can dispatch the incoming MXAccess
/// message that carries the value.
/// </summary>
/// <param name="serverHandle">The MXAccess server handle.</param>
/// <param name="tagAddresses">The tag addresses to read.</param>
/// <param name="timeout">The timeout per tag.</param>
/// <param name="pumpStep">Action invoked on each poll iteration.</param>
public IReadOnlyList<BulkReadResult> ReadBulk(
int serverHandle,
IReadOnlyList<string> tagAddresses,
@@ -50,6 +50,7 @@ public sealed class MxAccessStaSession : IWorkerRuntimeSession
/// <see cref="StartAsync(string, int, CancellationToken)"/>; pass <c>null</c> to opt out
/// of alarm-side commands.
/// </summary>
/// <param name="alarmCommandHandlerFactory">Factory that constructs the alarm-command handler.</param>
internal MxAccessStaSession(Func<MxAccessEventQueue, Action, IAlarmCommandHandler>? alarmCommandHandlerFactory)
: this(
new StaRuntime(),
@@ -130,6 +131,11 @@ public sealed class MxAccessStaSession : IWorkerRuntimeSession
/// pass <c>null</c> to opt out of alarm-side commands (the worker rejects
/// them with an "alarm consumer not configured" diagnostic).
/// </summary>
/// <param name="staRuntime">STA thread runtime.</param>
/// <param name="factory">MXAccess COM object factory.</param>
/// <param name="eventSink">Event sink for MXAccess events.</param>
/// <param name="eventQueue">Event queue for buffering MXAccess events.</param>
/// <param name="alarmCommandHandlerFactory">Factory that constructs the alarm-command handler.</param>
public MxAccessStaSession(
StaRuntime staRuntime,
IMxAccessComObjectFactory factory,
@@ -57,6 +57,9 @@ public sealed class MxAccessValueCache
}
/// <summary>Tries to read the most recent cached value for the handle pair.</summary>
/// <param name="serverHandle">MXAccess server handle.</param>
/// <param name="itemHandle">MXAccess item handle.</param>
/// <param name="value">The cached value if found.</param>
public bool TryGet(
int serverHandle,
int itemHandle,
@@ -74,6 +77,8 @@ public sealed class MxAccessValueCache
/// when an item is unregistered so stale values are not served to a
/// subsequent ReadBulk after a tag is removed and re-added.
/// </summary>
/// <param name="serverHandle">MXAccess server handle.</param>
/// <param name="itemHandle">MXAccess item handle.</param>
public void Remove(
int serverHandle,
int itemHandle)
@@ -95,6 +100,7 @@ public sealed class MxAccessValueCache
/// <param name="sinceVersion">Version snapshot captured before the wait.</param>
/// <param name="deadlineUtc">Absolute UTC deadline.</param>
/// <param name="pumpStep">Action that pumps any pending Windows messages.</param>
/// <param name="value">The cached value if the update was received before the deadline.</param>
/// <param name="pollIntervalMs">How long to sleep between pump cycles. Default 5 ms.</param>
public bool TryWaitForUpdate(
int serverHandle,
@@ -129,6 +135,8 @@ public sealed class MxAccessValueCache
}
/// <summary>Returns the current version for a handle pair, or 0 if no entry exists.</summary>
/// <param name="serverHandle">MXAccess server handle.</param>
/// <param name="itemHandle">MXAccess item handle.</param>
public ulong CurrentVersion(
int serverHandle,
int itemHandle)
@@ -158,6 +166,11 @@ public sealed class MxAccessValueCache
public readonly struct CachedValue
{
/// <summary>Initializes a new cached value snapshot.</summary>
/// <param name="version">Version counter incremented on each update.</param>
/// <param name="value">The MXAccess value.</param>
/// <param name="quality">The MXAccess quality code.</param>
/// <param name="sourceTimestamp">The source timestamp of the value.</param>
/// <param name="statuses">The MXAccess status codes.</param>
public CachedValue(
ulong version,
MxValue value,
@@ -9,18 +9,32 @@ namespace ZB.MOM.WW.MxGateway.Worker.MxAccess;
/// </summary>
public sealed class MxAlarmSnapshotRecord
{
/// <summary>Gets or sets the unique alarm identifier.</summary>
public Guid AlarmGuid { get; set; }
/// <summary>Gets or sets the UTC timestamp of the transition.</summary>
public DateTime TransitionTimestampUtc { get; set; }
/// <summary>Gets or sets the provider node name.</summary>
public string ProviderNode { get; set; } = string.Empty;
/// <summary>Gets or sets the provider name.</summary>
public string ProviderName { get; set; } = string.Empty;
/// <summary>Gets or sets the alarm group.</summary>
public string Group { get; set; } = string.Empty;
/// <summary>Gets or sets the tag name.</summary>
public string TagName { get; set; } = string.Empty;
/// <summary>Gets or sets the alarm type.</summary>
public string Type { get; set; } = string.Empty;
/// <summary>Gets or sets the alarm value.</summary>
public string Value { get; set; } = string.Empty;
/// <summary>Gets or sets the alarm limit.</summary>
public string Limit { get; set; } = string.Empty;
/// <summary>Gets or sets the alarm priority.</summary>
public int Priority { get; set; }
/// <summary>Gets or sets the alarm state.</summary>
public MxAlarmStateKind State { get; set; }
/// <summary>Gets or sets the operator node name.</summary>
public string OperatorNode { get; set; } = string.Empty;
/// <summary>Gets or sets the operator name.</summary>
public string OperatorName { get; set; } = string.Empty;
/// <summary>Gets or sets the alarm comment.</summary>
public string AlarmComment { get; set; } = string.Empty;
}
@@ -9,6 +9,7 @@ namespace ZB.MOM.WW.MxGateway.Worker.MxAccess;
/// </summary>
public sealed class MxAlarmTransitionEvent : EventArgs
{
/// <summary>Gets or sets the latest alarm snapshot record.</summary>
public MxAlarmSnapshotRecord Record { get; set; } = new MxAlarmSnapshotRecord();
/// <summary>
@@ -74,6 +74,8 @@ public sealed class WnWrapAlarmConsumer : IMxAccessAlarmConsumer
/// <summary>
/// Test seam / explicit construction.
/// </summary>
/// <param name="client">The COM alarm consumer instance.</param>
/// <param name="maxAlarmsPerFetch">Maximum alarms per fetch call.</param>
public WnWrapAlarmConsumer(
wwAlarmConsumerClass client,
int maxAlarmsPerFetch)
@@ -393,6 +395,7 @@ public sealed class WnWrapAlarmConsumer : IMxAccessAlarmConsumer
/// silently dropped (no fault is recorded — the next poll will
/// resync).
/// </summary>
/// <param name="xml">The XML snapshot payload.</param>
public static Dictionary<Guid, MxAlarmSnapshotRecord> ParseSnapshotXml(string xml)
{
Dictionary<Guid, MxAlarmSnapshotRecord> records =
@@ -455,6 +458,8 @@ public sealed class WnWrapAlarmConsumer : IMxAccessAlarmConsumer
/// dashes (e.g. <c>"BCC4705395424D65BDAABCDEA6A32A73"</c>). Convert
/// to <see cref="Guid"/>'s canonical 8-4-4-4-12 layout.
/// </summary>
/// <param name="hex">The 32-character hex GUID string.</param>
/// <param name="guid">The parsed GUID, or Empty if parsing fails.</param>
public static bool TryParseHexGuid(string? hex, out Guid guid)
{
guid = Guid.Empty;
@@ -481,6 +486,7 @@ public sealed class WnWrapAlarmConsumer : IMxAccessAlarmConsumer
/// cleanly, fall back to a permissive ALL-priority/ALL-state form
/// so the worker doesn't fail to start.
/// </summary>
/// <param name="subscription">The subscription expression.</param>
internal static string ComposeXmlAlarmQuery(string subscription)
{
string node = Environment.MachineName;