de8d5e91ce
Live investigation (direct from a VPN host to the 2023 R2 historian's real WCF port) showed the certificate transport + NegotiateAuthentication auth work cross-platform, and that the event-read chain needs the 0x501 event connection mode for CM_EVENT RegisterTags to succeed (0x402/0x401 fail). Even with registration succeeding over a window that has events, StartEventQuery returns a 0-row header and long-polls — the same server-side per-connection row gate proven for gRPC. Adds: EventReadConnectionModeOverride (diagnostic), and spike knobs — cross-platform cert gate, version-check bypass, per-call timeout, overall budget with phase-diagnostic dump, connection-mode override. Claude-Session: https://claude.ai/code/session_012SDSQ3AcaXqPcBtDESBRii
97 lines
4.9 KiB
C#
97 lines
4.9 KiB
C#
using AVEVA.Historian.Client.Models;
|
|
|
|
namespace AVEVA.Historian.Client;
|
|
|
|
public sealed class HistorianClientOptions
|
|
{
|
|
public const int DefaultPort = 32568;
|
|
|
|
/// <summary>Default TCP port of the 2023 R2 Historian Client Access Point gRPC endpoint.</summary>
|
|
public const int DefaultGrpcPort = 32565;
|
|
|
|
public required string Host { get; init; }
|
|
|
|
public int Port { get; init; } = DefaultPort;
|
|
|
|
public TimeSpan ConnectTimeout { get; init; } = TimeSpan.FromSeconds(5);
|
|
|
|
public TimeSpan RequestTimeout { get; init; } = TimeSpan.FromSeconds(30);
|
|
|
|
public string UserName { get; init; } = string.Empty;
|
|
|
|
public string Password { get; init; } = string.Empty;
|
|
|
|
public bool IntegratedSecurity { get; init; }
|
|
|
|
public bool Compression { get; init; }
|
|
|
|
public HistorianConnectionKind ConnectionKind { get; init; } = HistorianConnectionKind.Process;
|
|
|
|
public HistorianTransport Transport { get; init; } = HistorianTransport.LocalPipe;
|
|
|
|
public string TargetSpn { get; init; } = @"NT SERVICE\aahClientAccessPoint";
|
|
|
|
/// <summary>
|
|
/// When true, the WCF channel factories used by the SDK accept the server's
|
|
/// X.509 certificate without chain validation. Useful when connecting to a
|
|
/// development / on-prem Historian whose <c>/HistCert</c> endpoint presents an
|
|
/// installer-generated self-signed cert that isn't in the local trust store
|
|
/// (notably .NET WCF on Linux ignores the system CA bundle for its own
|
|
/// X509Chain checks). Default false; do not enable in production where the
|
|
/// server's identity matters.
|
|
/// </summary>
|
|
public bool AllowUntrustedServerCertificate { get; init; }
|
|
|
|
/// <summary>
|
|
/// Overrides the expected DNS identity in the endpoint address — set this to
|
|
/// whatever DNS name the server's certificate actually claims (often
|
|
/// <c>localhost</c> on installer-generated AVEVA Historian certificates) when
|
|
/// connecting via IP address or a hostname that doesn't match the cert SAN/CN.
|
|
/// Without this override WCF rejects the channel with
|
|
/// "Identity check failed for outgoing message". Has no effect on transports
|
|
/// that don't validate a server certificate.
|
|
/// </summary>
|
|
public string? ServerDnsIdentity { get; init; }
|
|
|
|
/// <summary>
|
|
/// Optional WCF "Via" address (e.g. <c>net.tcp://host:42568</c>). When set, the SDK's WCF
|
|
/// channel factories <b>connect</b> to this address while still addressing the SOAP message
|
|
/// <c>To</c> the logical endpoint built from <see cref="Host"/>/<see cref="Port"/>. Use this when
|
|
/// the Historian is reached through a port-forwarding tunnel or proxy whose local port differs
|
|
/// from the server's real service port: point <see cref="Host"/>/<see cref="Port"/> at the
|
|
/// server's real endpoint (so the server's WCF AddressFilter matches) and set this to the tunnel
|
|
/// endpoint. Has no effect on the gRPC transport. Default null (connect == address).
|
|
/// </summary>
|
|
public string? ConnectViaAddress { get; init; }
|
|
|
|
/// <summary>
|
|
/// Diagnostic override for the native OpenConnection mode the WCF event-read chain uses (default
|
|
/// <c>0x402</c>, read-only process). Set to e.g. <c>0x501</c> (event) or <c>0x401</c> (write-enabled)
|
|
/// to probe whether CM_EVENT registration / event-row retrieval needs a different connection type on a
|
|
/// 2023 R2 server. Null = the default read-only process mode. Intended for protocol investigation.
|
|
/// </summary>
|
|
public uint? EventReadConnectionModeOverride { get; init; }
|
|
|
|
/// <summary>
|
|
/// For <see cref="HistorianTransport.RemoteGrpc"/>: when true the channel uses TLS
|
|
/// (<c>https://</c>); when false it uses plaintext (<c>http://</c>). Matches the stock
|
|
/// 2023 R2 client's <c>securedConnection</c> flag. The TLS host is taken from
|
|
/// <see cref="ServerDnsIdentity"/> when set (to match the server certificate's name),
|
|
/// otherwise <see cref="Host"/>. When <see cref="AllowUntrustedServerCertificate"/> is
|
|
/// true the server certificate chain is not validated. Default false.
|
|
/// </summary>
|
|
public bool GrpcUseTls { get; init; }
|
|
|
|
/// <summary>
|
|
/// When true (default) the SDK verifies, at connect time, that the Historian server
|
|
/// reports the native interface versions its byte serializers were built against
|
|
/// (History=11, Retrieval=4, Transaction=2 — evidence from a live AVEVA Historian 2020
|
|
/// server). A mismatch throws <see cref="ProtocolEvidenceMissingException"/> rather than
|
|
/// risk misparsing version-framed native buffers. Set false only when you have
|
|
/// independently confirmed wire compatibility with a different server version — e.g.
|
|
/// when bringing up a 2023 R2 gRPC server whose reported interface integers have not yet
|
|
/// been captured. See <see cref="HistorianServerVersionGate"/>.
|
|
/// </summary>
|
|
public bool VerifyServerInterfaceVersion { get; init; } = true;
|
|
}
|