UWP HttpRequestMessage.TransportInformation missing
本文关键字:missing TransportInformation HttpRequestMessage UWP | 更新日期: 2023-09-27 18:18:07
我的UWP应用程序连接到http(s)服务器来执行一些数据传输。在建立TLS连接时,如果由于握手失败而导致失败,则http prequestmessage。TransportInformation提供了关于特定错误和服务器证书的信息,我们使用它们向最终用户显示消息。
在我将我的开发机器升级到Windows 10 build 1607并将应用重新定位为"Windows 10周年纪念版(10.0;建立14393年)"。更早的版本是"Windows 10 (10.0;建立10586年)"。
在此更改后,HttpRequestMessage中的所有字段。TransportInformation为空。但是,异常和对应的HRESULT清楚地表明SSL错误(此处为不受信任的服务器证书)。
我尝试使用StreamSocket,并确定足够的SSL握手错误上来了,但StreamSocket。信息属性已正确填写了所有字段(服务器证书,错误等),因此可以检查它们。
记录服务器证书是自签名的,使用SHA1指纹/签名算法。
在下面的代码片段中,req。ConnectToServerHttpAsync中的TransprtInformation从不提供服务端证书,而streamSock。信息在ConnectToServerAsync中提供了服务器证书的详细信息。
问题:这是新SDK中的错误,还是我必须在build 14393上与HttpClient做一些不同的事情来获取传输信息?在MSDN或SO上没有找到任何关于此行为的内容,因此发布。
private async Task ConnectToServerHttpAsync(Uri connectUri)
{
HttpRequestMessage req = null;
try
{
using (HttpBaseProtocolFilter bpf = new HttpBaseProtocolFilter())
{
bpf.AllowUI = false;
using (HttpClient httpClient = new HttpClient(bpf))
{
req = new HttpRequestMessage(HttpMethod.Get, connectUri);
using (HttpResponseMessage res = await httpClient.SendRequestAsync(req))
{
Status = ((int)(res.StatusCode)) + " " + res.ReasonPhrase;
}
}
}
}
catch (Exception ex)
{
SocketErrorStatus eSocketErrorStatus = SocketError.GetStatus(ex.HResult);
Status = eSocketErrorStatus.ToString();
Status = req?.TransportInformation?.ServerCertificate?.ToString() ?? "No server certificate.";
}
req?.Dispose();
}
private async Task ConnectToServerAsync(Uri uriToConnect)
{
StreamSocket streamSock = new StreamSocket();
HostName hostName = new HostName(uriToConnect.Host);
try
{
await streamSock.ConnectAsync(hostName, uriToConnect.Port.ToString(), SocketProtectionLevel.Tls12);
Status = "Connected.";
streamSock.Dispose();
}
catch (Exception ex)
{
SocketErrorStatus eSocketErrorStatus = SocketError.GetStatus(ex.HResult);
Status = eSocketErrorStatus.ToString();
Status = "Certificate details:";
Status = "Friendly name: " + streamSock.Information.ServerCertificate.FriendlyName;
Status = "Issuer: " + streamSock.Information.ServerCertificate.Issuer;
Status = "SignatureAlgorithmName: " + streamSock.Information.ServerCertificate.SignatureAlgorithmName;
Status = "SignatureHashAlgorithmName: " + streamSock.Information.ServerCertificate.SignatureHashAlgorithmName;
Status = "Subject: " + streamSock.Information.ServerCertificate.Subject;
Status = "ValidFrom: " + streamSock.Information.ServerCertificate.ValidFrom.ToString();
Status = "ValidTo: " + streamSock.Information.ServerCertificate.ValidTo.ToString();
ServerCert = streamSock.Information.ServerCertificate;
}
}
看来我可能已经找到了一个解决方案(由于MS似乎没有很好地记录API行为更改而需要)。显然,如果证书的操作系统默认验证失败,则在HttpRequestMessage::TransportInformation属性中不再提供服务器证书详细信息。要获取服务器证书的详细信息,需要添加(build 13493中新增的)ServerCustomValidationRequested事件的处理程序。对于我的特定情况(自签名的、不受信任的证书),我还必须添加ChainValidationResult。不受HttpBaseProtocolFilter中IgnorableServerCertificateErrors属性的信任。在此之后,触发了ServerCustomValidationRequested,我可以获得服务器证书的详细信息。修改后的函数如下:
顺便说一下,我还注意到一旦ServerCustomValidationRequested被处理并且证书被拒绝,使用HttpServerCustomValidationRequestedEventArgs::Reject, HttpRequestMessage。TransportInformation确实得到了填充。
如果MS能更好地记录这种行为改变,我就可以避免很多时间浪费和悲伤。希望对大家有所帮助。
private async Task ConnectToServerHttpAsync(Uri connectUri)
{
HttpRequestMessage req = null;
try
{
using (HttpBaseProtocolFilter bpf = new HttpBaseProtocolFilter())
{
bpf.AllowUI = false;
bpf.ServerCustomValidationRequested += ServerCustomValidationRequested;
bpf.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
using (HttpClient httpClient = new HttpClient(bpf))
{
req = new HttpRequestMessage(HttpMethod.Get, connectUri);
using (HttpResponseMessage res = await httpClient.SendRequestAsync(req))
{
Status = ((int)(res.StatusCode)) + " " + res.ReasonPhrase;
}
}
}
}
catch (Exception ex)
{
SocketErrorStatus eSocketErrorStatus = SocketError.GetStatus(ex.HResult);
Status = eSocketErrorStatus.ToString();
Status = req?.TransportInformation?.ServerCertificate?.ToString() ?? "No server certificate.";
}
req?.Dispose();
}
private void ServerCustomValidationRequested(HttpBaseProtocolFilter sender, HttpServerCustomValidationRequestedEventArgs customValidationArgs)
{
Status = "-----ServerCustomValidationRequested-----";
Status = "Certificate details:";
Status = "Friendly name: " + customValidationArgs.ServerCertificate.FriendlyName;
Status = "Issuer: " + customValidationArgs.ServerCertificate.Issuer;
Status = "SignatureAlgorithmName: " + customValidationArgs.ServerCertificate.SignatureAlgorithmName;
Status = "SignatureHashAlgorithmName: " + customValidationArgs.ServerCertificate.SignatureHashAlgorithmName;
Status = "Subject: " + customValidationArgs.ServerCertificate.Subject;
Status = "ValidFrom: " + customValidationArgs.ServerCertificate.ValidFrom.ToString();
Status = "ValidTo: " + customValidationArgs.ServerCertificate.ValidTo.ToString();
ServerCert = customValidationArgs.ServerCertificate;
// Validate the server certificate as required.
// customValidationArgs.Reject();
}