Add component-level documentation for all 14 server subsystems
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>
This commit is contained in:
182
docs/Configuration.md
Normal file
182
docs/Configuration.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# 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:
|
||||
|
||||
```csharp
|
||||
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:
|
||||
|
||||
1. `appsettings.json` -- base configuration (required)
|
||||
2. `appsettings.{DOTNET_ENVIRONMENT}.json` -- environment-specific overlay (optional)
|
||||
3. 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`** -- When `true`, the node manager creates `AlarmConditionState` nodes for alarm attributes and monitors `InAlarm` transitions. Disabled by default because alarm tracking adds per-attribute overhead.
|
||||
- **`Historian.Enabled`** -- When `true`, the service creates a `HistorianDataSource` connected 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`** -- When `true`, 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.Port` must be between 1 and 65535
|
||||
- `OpcUa.GalaxyName` must not be empty
|
||||
- `MxAccess.ClientName` must not be empty
|
||||
- `GalaxyRepository.ConnectionString` must 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`:
|
||||
|
||||
```csharp
|
||||
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
|
||||
|
||||
```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
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user