Exception Details: System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel

Programming, error messages and sample code > ASP.NET
If you get the following error message while calling third-party service with client certificate authentication, it means your application misses the matched version of System.Net.Http.dll or your application codes cannot read the certificate file from the correct store location.
 

Server Error in '/' Application.


The request was aborted: Could not create SSL/TLS secure channel.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Stack Trace:
[WebException: The request was aborted: Could not create SSL/TLS secure channel.]
   System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context) +333
   System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar) +112
[HttpRequestException: An error occurred while sending the request.]
[AggregateException: One or more errors occurred.]
   System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions) +4247326
   System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification) +12576612
   System.Threading.Tasks.Task`1.get_Result() +34
   WebApplication1.Default.Page_Load(Object sender, EventArgs e) in C:\xxx\xxx.aspx.cs:30
   System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +52
   System.Web.UI.Control.OnLoad(EventArgs e) +97
   System.Web.UI.Control.LoadRecursive() +61
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +693
 
 
 
 

Solution:

Read the certificate from your site .cer/.pfx file instead of the server store.
 
Upload the System.Net.Http.dll to your site folder, it is "bin" folder if you use .net framework, and it is your site root folder if you use .net core.
 
Configure X509KeyStorageFlags to MachineKeySet in application codes, "Private keys are stored in the local computer store rather than the current user store".
 
 
full sample codes:
single .aspx page
 
<%@ Page Language="C#" Debug="true" %>
<% @Import Namespace="System.Net.Http" %>    // must upload this DLL to your site folder
<% @Import Namespace="System.Security.Cryptography.X509Certificates" %>

<script runat="server">
   protected void Page_Load(object sender, EventArgs ea)
   {
        X509Certificate2 certificate = new X509Certificate2(
            Server.MapPath("your_certificate.pfx"),  // set certificate file path with file name
            "certificate_import_password",           // set the import password
            X509KeyStorageFlags.MachineKeySet        // set the storage flag
        );

        HttpClientHandler handler = new HttpClientHandler()
        {
            ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => {
                return true;
            }
        };

        handler.ClientCertificates.Add(certificate);

        HttpClient httpClient = new HttpClient(handler);

        // design request context, it is optional
        HttpContent context = new StringContent("string_content", "encoding_type", "content_type");

        // initialize the request
        var response = httpClient.PostAsync("your_service_url", context).Result;

        // continue to do something with the respone
   }

</script>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
   <title></title>
</head>
<body>
   <form id="form1" runat="server">
   <div>
   
   </div>
   </form>
</body>
</html>

Additional

The above codes will store the whole settings in memory, in case you update the X509KeyStorageFlags, certificate file, your website still read the old settings, please restart your application pool from Control Panel to fix the cache issue.