using ZB.MOM.WW.Configuration; using ZB.MOM.WW.OtOpcUa.OpcUaServer; namespace ZB.MOM.WW.OtOpcUa.Host.Configuration; /// /// Fail-fast startup validator for , built on the /// shared ZB.MOM.WW.Configuration . The C# /// defaults are all valid, so a host with no explicit "OpcUa" section passes untouched; /// the validator exists to reject explicit prod/env overrides before the OPC UA SDK boots. /// Identity/transport essentials (ApplicationName, ApplicationUri, /// PublicHostname, PkiStoreRoot, OpcUaPort) must be present/valid and at /// least one security profile must be enabled. Optional fields — ApplicationConfigPath, /// PeerApplicationUris, AutoAcceptUntrustedClientCertificates, and /// ProductUri — are intentionally not validated. Failure messages carry the real /// "OpcUa:" section prefix matching the bound configuration section. /// public sealed class OpcUaApplicationHostOptionsValidator : OptionsValidatorBase { /// protected override void Validate(ValidationBuilder builder, OpcUaApplicationHostOptions o) { builder.Required(o.ApplicationName, "OpcUa:ApplicationName"); builder.Required(o.ApplicationUri, "OpcUa:ApplicationUri"); builder.Required(o.PublicHostname, "OpcUa:PublicHostname"); builder.Required(o.PkiStoreRoot, "OpcUa:PkiStoreRoot"); builder.Port(o.OpcUaPort, "OpcUa:OpcUaPort"); // EnabledSecurityProfiles is declared as IList — that interface does not derive from // IReadOnlyCollection, so it can't bind to MinCount's IReadOnlyCollection parameter // directly. ToList() bridges to the shared primitive while preserving the count (and message). builder.MinCount(o.EnabledSecurityProfiles?.ToList(), 1, "OpcUa:EnabledSecurityProfiles"); } }