几年前,我设法使我们的代码包含一个客户端证书。(参见Elasticsearch NEST HttpClientHandler证书的最后一篇文章)。我试图在另一个项目中使用相同的代码,但它失败了:
"ExceptionMessage": "The request was aborted: Could not create SSL/TLS secure channel."
大多数建议都围绕设置ServicePointManager。安全协议= Tls12;我已经试过了所有的组合。
我试图缩小范围,只是添加了
直接使用HttpClientHandler
示例来自https://damienbod.com/2019/09/07/using-certificate-authentication-with-ihttpclientfactory-and-httpclient/
private async Task<JsonDocument> GetApiDataUsingHttpClientHandler()
{
var cert = new X509Certificate2(Path.Combine(_environment.ContentRootPath, "sts_dev_cert.pfx"), "1234");
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(cert);
var client = new HttpClient(handler);
var request = new HttpRequestMessage()
{
RequestUri = new Uri("https://localhost:44379/api/values"),
Method = HttpMethod.Get,
};
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
var data = JsonDocument.Parse(responseContent);
return data;
}
throw new ApplicationException($"Status code: {response.StatusCode}, Error: {response.ReasonPhrase}");
}
这在一个方法中完成了所有的事情(读取证书,附加到处理程序,并发出请求)。如果我在一个独立的项目中运行这段代码,它可以正常工作。我试图从服务结构中托管的WebApi运行它。在调试时,我可以看到获得了证书并正确地添加到处理程序中。调用从来没有离开我的代码(即从未发出)与Fiddler验证。
我们在Service Fabric的另一个解决方案中做了同样的事情,并且一切正常。
还有什么可能被遗漏的吗?
谢谢!
注:添加完整异常
{
"Message": "An error has occurred.",
"ExceptionMessage": "An error occurred while sending the request.",
"ExceptionType": "System.Net.Http.HttpRequestException",
"StackTrace": " at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()rn at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)rn at System.Net.Http.HttpClient.<FinishSendAsyncBuffered>d__58.MoveNext()rn--- End of stack trace from previous location where exception was thrown ---rn at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()rn at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)rn at System.Threading.Tasks.TaskHelpersExtensions.<CastToObject>d__3`1.MoveNext()rn--- End of stack trace from previous location where exception was thrown ---rn at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()rn at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)rn at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()rn--- End of stack trace from previous location where exception was thrown ---rn at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()rn at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)rn at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()rn--- End of stack trace from previous location where exception was thrown ---rn at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()rn at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()rn--- End of stack trace from previous location where exception was thrown ---rn at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()rn at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)rn at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()rn--- End of stack trace from previous location where exception was thrown ---rn at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()rn at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)rn at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()rn--- End of stack trace from previous location where exception was thrown ---rn at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()rn at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)rn at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()rn--- End of stack trace from previous location where exception was thrown ---rn at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()rn at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()rn--- End of stack trace from previous location where exception was thrown ---rn at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()rn at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)rn at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()",
"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "The request was aborted: Could not create SSL/TLS secure channel.",
"ExceptionType": "System.Net.WebException",
"StackTrace": " at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)rn at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)"
}
}
通过比较我们的两个解决方案,我发现了一些解决方案。我不知道这到底是怎么回事,但确实管用。我认为它需要某种用户上下文来打开通道。
在Service Fabric项目的AppManifest.xml中,我在底部添加了这段代码:
<Principals>
<Users>
<User Name="SomeUserName">
<MemberOf>
<SystemGroup Name="Administrators" />
</MemberOf>
</User>
</Users>
</Principals>
<Policies>
<DefaultRunAsPolicy UserRef="SomeUserName" />
</Policies>
注意"SomeUserName"实际上不对应于我系统上的任何用户帐户。也许它正在内存中创建一个用户上下文。