diff --git a/src/AVEVA.Historian.Client/HistorianClientOptions.cs b/src/AVEVA.Historian.Client/HistorianClientOptions.cs index 21eed2f..60c6d06 100644 --- a/src/AVEVA.Historian.Client/HistorianClientOptions.cs +++ b/src/AVEVA.Historian.Client/HistorianClientOptions.cs @@ -38,4 +38,15 @@ public sealed class HistorianClientOptions /// server's identity matters. /// public bool AllowUntrustedServerCertificate { get; init; } + + /// + /// Overrides the expected DNS identity in the endpoint address — set this to + /// whatever DNS name the server's certificate actually claims (often + /// localhost 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. + /// + public string? ServerDnsIdentity { get; init; } } diff --git a/src/AVEVA.Historian.Client/Wcf/HistorianWcfBindingFactory.cs b/src/AVEVA.Historian.Client/Wcf/HistorianWcfBindingFactory.cs index 9838178..7381696 100644 --- a/src/AVEVA.Historian.Client/Wcf/HistorianWcfBindingFactory.cs +++ b/src/AVEVA.Historian.Client/Wcf/HistorianWcfBindingFactory.cs @@ -144,19 +144,22 @@ internal static class HistorianWcfBindingFactory CreateEndpointAddress(options.Host, options.Port, HistorianWcfServiceNames.Retrieval)), HistorianTransport.RemoteTcpCertificate => ( CreateMdasNetTcpCertificateBinding(timeout), - CreateEndpointAddress(options.Host, options.Port, HistorianWcfServiceNames.HistoryCertificate), + CreateEndpointAddress(options.Host, options.Port, HistorianWcfServiceNames.HistoryCertificate, options.ServerDnsIdentity), CreateMdasNetTcpBinding(timeout), CreateEndpointAddress(options.Host, options.Port, HistorianWcfServiceNames.Retrieval)), _ => throw new NotSupportedException($"Transport {options.Transport} is not supported.") }; } - public static EndpointAddress CreateEndpointAddress(string host, int port, string serviceName) + public static EndpointAddress CreateEndpointAddress(string host, int port, string serviceName, string? dnsIdentity = null) { ArgumentException.ThrowIfNullOrWhiteSpace(host); ArgumentException.ThrowIfNullOrWhiteSpace(serviceName); - return new EndpointAddress($"{Scheme}://{host}:{port}/{serviceName}"); + Uri uri = new($"{Scheme}://{host}:{port}/{serviceName}"); + return string.IsNullOrWhiteSpace(dnsIdentity) + ? new EndpointAddress(uri) + : new EndpointAddress(uri, new DnsEndpointIdentity(dnsIdentity)); } public static EndpointAddress CreatePipeEndpointAddress(string host, string serviceName)