Files
scadalink-design/deprecated/lmxproxy/docs/requirements/Component-MxAccessClient.md
Joseph Doherty 9dccf8e72f deprecate(lmxproxy): move all LmxProxy code, tests, and docs to deprecated/
LmxProxy is no longer needed. Moved the entire lmxproxy/ workspace, DCL
adapter files, and related docs to deprecated/. Removed LmxProxy registration
from DataConnectionFactory, project reference from DCL, protocol option from
UI, and cleaned up all requirement docs.
2026-04-08 15:56:23 -04:00

6.0 KiB

Component: MxAccessClient

Purpose

The core component that wraps the ArchestrA MXAccess COM API, providing connection management, tag read/write operations, and subscription-based value change notifications. This is the bridge between the gRPC service layer and AVEVA System Platform.

Location

src/ZB.MOM.WW.LmxProxy.Host/MxAccess/MxAccessClient.cs — partial class split across 6 files:

  • MxAccessClient.cs — Main class, properties, disposal, factory.
  • MxAccessClient.Connection.cs — Connection lifecycle (connect, disconnect, reconnect, cleanup).
  • MxAccessClient.ReadWrite.cs — Read and write operations with retry and concurrency control.
  • MxAccessClient.Subscription.cs — Subscription management and stored subscription state.
  • MxAccessClient.EventHandlers.cs — COM event handlers (OnDataChange, OnWriteComplete, OperationComplete).
  • MxAccessClient.NestedTypes.cs — Internal types and enums.

Responsibilities

  • Manage the MXAccess COM object lifecycle (create, register, unregister, release).
  • Maintain connection state (Disconnected, Connecting, Connected, Disconnecting, Error, Reconnecting) and fire state change events.
  • Execute read and write operations against MXAccess with concurrency control via semaphores.
  • Manage tag subscriptions via MXAccess advise callbacks and store subscription state for reconnection.
  • Handle COM threading constraints (STA thread context via Task.Run).

1. Connection Lifecycle

1.1 Connect

ConnectAsync() wraps ConnectInternal() in Task.Run for STA thread context:

  1. Validates not disposed.
  2. Returns early if already connected.
  3. Sets state to Connecting.
  4. InitializeMxAccessConnection() — creates new LMXProxyServer COM object, wires event handlers (OnDataChange, OnWriteComplete, OperationComplete).
  5. RegisterWithMxAccess() — calls _lmxProxy.Register("ZB.MOM.WW.LmxProxy.Host"), stores the returned connection handle.
  6. Sets state to Connected.
  7. On error, calls Cleanup() and re-throws.

After successful connection, calls RecreateStoredSubscriptionsAsync() to restore any previously active subscriptions.

1.2 Disconnect

DisconnectAsync() wraps DisconnectInternal() in Task.Run:

  1. Checks IsConnected.
  2. Sets state to Disconnecting.
  3. RemoveAllSubscriptions() — unsubscribes all tags from MXAccess but retains subscription state in _storedSubscriptions for reconnection.
  4. UnregisterFromMxAccess() — calls _lmxProxy.Unregister(_connectionHandle).
  5. Cleanup() — removes event handlers, calls Marshal.ReleaseComObject(_lmxProxy) to force-release all COM references, nulls the proxy and resets the connection handle.
  6. Sets state to Disconnected.

1.3 Connection State

  • IsConnected property: _lmxProxy != null && _connectionState == Connected && _connectionHandle > 0.
  • ConnectionState enum: Disconnected, Connecting, Connected, Disconnecting, Error, Reconnecting.
  • ConnectionStateChanged event fires on all state transitions with previous state, current state, and optional message.

1.4 Auto-Reconnect

When AutoReconnect is enabled (default), the MonitorConnectionAsync loop runs continuously:

  • Checks IsConnected every MonitorIntervalSeconds (default 5 seconds).
  • On disconnect, attempts reconnect via semaphore-protected ConnectAsync().
  • On failure, logs warning and retries at the next interval.
  • Reconnection restores stored subscriptions automatically.

2. Thread Safety & COM Constraints

  • State mutations protected by lock (_lock).
  • COM operations wrapped in Task.Run for STA thread context (MXAccess is 32-bit COM).
  • Concurrency control: _readSemaphore and _writeSemaphore limit concurrent MXAccess operations to MaxConcurrentOperations (default 10, configurable).
  • Default max concurrency constant: DefaultMaxConcurrency = 10.

3. Read Operations

  • ReadAsync(address, ct) — Applies Polly retry policy, calls ReadSingleValueAsync(), returns Vtq.
  • ReadBatchAsync(addresses, ct) — Creates parallel tasks per address via ReadAddressWithSemaphoreAsync(). Each task acquires _readSemaphore before reading. Returns IReadOnlyDictionary<address, Vtq>.

4. Write Operations

  • WriteAsync(address, value, ct) — Applies Polly retry policy, calls WriteInternalAsync(address, value, ct).
  • WriteBatchAsync(values, ct) — Parallel tasks via WriteAddressWithSemaphoreAsync(). Each task acquires _writeSemaphore before writing.
  • WriteBatchAndWaitAsync(values, flagAddress, flagValue, responseAddress, responseValue, ct) — Writes batch, writes flag, polls response tag until match.

5. Subscription Management

  • Subscriptions stored in _storedSubscriptions for reconnection persistence.
  • SubscribeInternalAsync(addresses, callback, storeSubscription) — registers tags with MXAccess and stores subscription state.
  • RecreateStoredSubscriptionsAsync() — called after reconnect to re-subscribe all previously active tags without re-storing.
  • RemoveAllSubscriptions() — unsubscribes from MXAccess but retains _storedSubscriptions.

6. Event Handlers

  • OnDataChange — Fired by MXAccess when a subscribed tag value changes. Routes the update to the SubscriptionManager.
  • OnWriteComplete — Fired when an async write operation completes.
  • OperationComplete — General operation completion callback.

Dependencies

  • ArchestrA.MXAccess COM interop assembly (lib/ArchestrA.MXAccess.dll).
  • Polly — retry policies for read/write operations.
  • ConfigurationConnectionConfiguration for timeouts, concurrency limits, and auto-reconnect settings.

Interactions

  • GrpcServer (ScadaGrpcService) delegates all SCADA operations to MxAccessClient via the IScadaClient interface.
  • SubscriptionManager receives value change callbacks originating from MxAccessClient's COM event handlers.
  • HealthAndMetrics queries IsConnected and ConnectionState for health checks.
  • ServiceHost manages the MxAccessClient lifecycle (create at startup, dispose at shutdown).