Provides technical documentation covering OPC UA server, address space, Galaxy repository, MXAccess bridge, data types, read/write, subscriptions, alarms, historian, incremental sync, configuration, dashboard, service hosting, and CLI tool. Updates README with component documentation table. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
8.6 KiB
Configuration
Overview
The service loads configuration from appsettings.json at startup using the Microsoft.Extensions.Configuration stack. AppConfiguration is the root holder class that aggregates five typed sections: OpcUa, MxAccess, GalaxyRepository, Dashboard, and Historian. Each section binds to a dedicated POCO class with sensible defaults, so the service runs with zero configuration on a standard deployment.
Config Binding Pattern
The production constructor in OpcUaService builds the configuration pipeline and binds each JSON section to its typed class:
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? "Production"}.json", optional: true)
.AddEnvironmentVariables()
.Build();
_config = new AppConfiguration();
configuration.GetSection("OpcUa").Bind(_config.OpcUa);
configuration.GetSection("MxAccess").Bind(_config.MxAccess);
configuration.GetSection("GalaxyRepository").Bind(_config.GalaxyRepository);
configuration.GetSection("Dashboard").Bind(_config.Dashboard);
configuration.GetSection("Historian").Bind(_config.Historian);
This pattern uses IConfiguration.GetSection().Bind() rather than IOptions<T> because the service targets .NET Framework 4.8, where the full dependency injection container is not used.
Environment-Specific Overrides
The configuration pipeline supports three layers of override, applied in order:
appsettings.json-- base configuration (required)appsettings.{DOTNET_ENVIRONMENT}.json-- environment-specific overlay (optional)- Environment variables -- highest priority, useful for deployment automation
Set the DOTNET_ENVIRONMENT variable to load a named overlay file. For example, setting DOTNET_ENVIRONMENT=Staging loads appsettings.Staging.json if it exists.
Environment variables follow the standard Section__Property naming convention. For example, OpcUa__Port=5840 overrides the OPC UA port.
Configuration Sections
OpcUa
Controls the OPC UA server endpoint and session limits. Defined in OpcUaConfiguration.
| Property | Type | Default | Description |
|---|---|---|---|
Port |
int |
4840 |
TCP port the OPC UA server listens on |
EndpointPath |
string |
"/LmxOpcUa" |
Path appended to the host URI |
ServerName |
string |
"LmxOpcUa" |
Server name presented to OPC UA clients |
GalaxyName |
string |
"ZB" |
Galaxy name used as the OPC UA namespace |
MaxSessions |
int |
100 |
Maximum simultaneous OPC UA sessions |
SessionTimeoutMinutes |
int |
30 |
Idle session timeout in minutes |
AlarmTrackingEnabled |
bool |
false |
Enables AlarmConditionState nodes for alarm attributes |
MxAccess
Controls the MXAccess runtime connection used for live tag reads and writes. Defined in MxAccessConfiguration.
| Property | Type | Default | Description |
|---|---|---|---|
ClientName |
string |
"LmxOpcUa" |
Client name registered with MXAccess |
NodeName |
string? |
null |
Optional Galaxy node name to target |
GalaxyName |
string? |
null |
Optional Galaxy name for MXAccess reference resolution |
ReadTimeoutSeconds |
int |
5 |
Maximum wait for a live tag read |
WriteTimeoutSeconds |
int |
5 |
Maximum wait for a write acknowledgment |
MaxConcurrentOperations |
int |
10 |
Cap on concurrent MXAccess operations |
MonitorIntervalSeconds |
int |
5 |
Connectivity monitor probe interval |
AutoReconnect |
bool |
true |
Automatically re-establish dropped MXAccess sessions |
ProbeTag |
string? |
null |
Optional tag used to verify the runtime returns fresh data |
ProbeStaleThresholdSeconds |
int |
60 |
Seconds a probe value may remain unchanged before the connection is considered stale |
GalaxyRepository
Controls the Galaxy repository database connection used to build the OPC UA address space. Defined in GalaxyRepositoryConfiguration.
| Property | Type | Default | Description |
|---|---|---|---|
ConnectionString |
string |
"Server=localhost;Database=ZB;Integrated Security=true;" |
SQL Server connection string for the Galaxy database |
ChangeDetectionIntervalSeconds |
int |
30 |
How often the service polls for Galaxy deploy changes |
CommandTimeoutSeconds |
int |
30 |
SQL command timeout for repository queries |
ExtendedAttributes |
bool |
false |
Load extended Galaxy attribute metadata into the OPC UA model |
Dashboard
Controls the embedded HTTP status dashboard. Defined in DashboardConfiguration.
| Property | Type | Default | Description |
|---|---|---|---|
Enabled |
bool |
true |
Whether the status dashboard is hosted |
Port |
int |
8081 |
HTTP port for the dashboard endpoint |
RefreshIntervalSeconds |
int |
10 |
HTML auto-refresh interval in seconds |
Historian
Controls the Wonderware Historian connection for OPC UA historical data access. Defined in HistorianConfiguration.
| Property | Type | Default | Description |
|---|---|---|---|
Enabled |
bool |
false |
Enables OPC UA historical data access |
ConnectionString |
string |
"Server=localhost;Database=Runtime;Integrated Security=true;" |
Connection string for the Historian Runtime database |
CommandTimeoutSeconds |
int |
30 |
SQL command timeout for historian queries |
MaxValuesPerRead |
int |
10000 |
Maximum values returned per HistoryRead request |
Feature Flags
Three boolean properties act as feature flags that control optional subsystems:
OpcUa.AlarmTrackingEnabled-- Whentrue, the node manager createsAlarmConditionStatenodes for alarm attributes and monitorsInAlarmtransitions. Disabled by default because alarm tracking adds per-attribute overhead.Historian.Enabled-- Whentrue, the service creates aHistorianDataSourceconnected to the Wonderware Historian Runtime database and registers it with the OPC UA server host. Disabled by default because not all deployments have a Historian instance.GalaxyRepository.ExtendedAttributes-- Whentrue, the repository loads additional Galaxy attribute metadata beyond the core set needed for the address space. Disabled by default to minimize startup query time.
Configuration Validation
ConfigurationValidator.ValidateAndLog() runs at the start of OpcUaService.Start(). It logs every resolved configuration value at Information level and validates required constraints:
OpcUa.Portmust be between 1 and 65535OpcUa.GalaxyNamemust not be emptyMxAccess.ClientNamemust not be emptyGalaxyRepository.ConnectionStringmust not be empty
If validation fails, the service throws InvalidOperationException and does not start.
Test Constructor Pattern
OpcUaService provides an internal constructor that accepts pre-built dependencies instead of loading appsettings.json:
internal OpcUaService(
AppConfiguration config,
IMxProxy? mxProxy,
IGalaxyRepository? galaxyRepository,
IMxAccessClient? mxAccessClientOverride = null,
bool hasMxAccessClientOverride = false)
Integration tests use this constructor to inject substitute implementations of IMxProxy, IGalaxyRepository, and IMxAccessClient, bypassing the STA thread, COM interop, and SQL Server dependencies. The hasMxAccessClientOverride flag tells the service to use the injected IMxAccessClient directly instead of creating one from the IMxProxy on the STA thread.
Example appsettings.json
{
"OpcUa": {
"Port": 4840,
"EndpointPath": "/LmxOpcUa",
"ServerName": "LmxOpcUa",
"GalaxyName": "ZB",
"MaxSessions": 100,
"SessionTimeoutMinutes": 30,
"AlarmTrackingEnabled": false
},
"MxAccess": {
"ClientName": "LmxOpcUa",
"NodeName": null,
"GalaxyName": null,
"ReadTimeoutSeconds": 5,
"WriteTimeoutSeconds": 5,
"MaxConcurrentOperations": 10,
"MonitorIntervalSeconds": 5,
"AutoReconnect": true,
"ProbeTag": null,
"ProbeStaleThresholdSeconds": 60
},
"GalaxyRepository": {
"ConnectionString": "Server=localhost;Database=ZB;Integrated Security=true;",
"ChangeDetectionIntervalSeconds": 30,
"CommandTimeoutSeconds": 30,
"ExtendedAttributes": false
},
"Dashboard": {
"Enabled": true,
"Port": 8081,
"RefreshIntervalSeconds": 10
},
"Historian": {
"Enabled": false,
"ConnectionString": "Server=localhost;Database=Runtime;Integrated Security=true;",
"CommandTimeoutSeconds": 30,
"MaxValuesPerRead": 10000
}
}