1

I'm using HttpClient (.NET Core3.1) to make get requests from multiple sources. I'm using only one instance instatiated in the constructor as follows:

_httpClient = new HttpClient();

_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
_httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("covid19App", "2.0"));

and the get call method is as follows:

private HttpResponseMessage Get(string url)
{
    var response = _httpClient.GetAsync(url).Result;

    int count = 0;

    while (count < 3 && response.IsSuccessStatusCode)
    {
        response = _httpClient.GetAsync(url).Result;
        count++;

    }

    return response;

}

I didn't have any issue with the above logic until my SSL certificate expired. Now calls to one of the sources is returning an exception The SSL connection could not be established, see inner exception(Please see below for inner exception detail)

After some research I used two approaches to solve the issue but the problem persists.

Approach 1

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = (sender, certificate, chain, errors) => true;

_httpClient = new HttpClient(handler);

Approach 2:

ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;

_httpClient = new HttpClient();

_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
_httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("covid19App", "2.0"));

So is there any other approaches to solve this issue?

Inner exception: The SSL connection could not be established, see inner exception. => Authentication failed, see inner exception => The message received was unexpected or badly formatted.

EDIT: Added entire exception body

{
   "ClassName":"System.AggregateException",
   "Message":"One or more errors occurred.",
   "Data":null,
   "InnerException":{
      "StackTrace":"   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)\r\n   at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)\r\n   at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n   at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)\r\n   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n   at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n   at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)",
      "Message":"The SSL connection could not be established, see inner exception.",
      "Data":{
         
      },
      "InnerException":{
         "ClassName":"System.Security.Authentication.AuthenticationException",
         "Message":"Authentication failed, see inner exception.",
         "Data":null,
         "InnerException":{
            "ClassName":"System.ComponentModel.Win32Exception",
            "Message":"The message received was unexpected or badly formatted.",
            "Data":null,
            "InnerException":null,
            "HelpURL":null,
            "StackTraceString":null,
            "RemoteStackTraceString":null,
            "RemoteStackIndex":0,
            "ExceptionMethod":null,
            "HResult":-2147467259,
            "Source":null,
            "WatsonBuckets":null,
            "NativeErrorCode":-2146893018
         },
         "HelpURL":null,
         "StackTraceString":"   at System.Net.Security.SslStream.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)\r\n   at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)\r\n   at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)\r\n   at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)\r\n   at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)\r\n   at System.Net.Security.SslStream.PartialFrameCallback(AsyncProtocolRequest asyncRequest)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Net.Security.SslStream.ThrowIfExceptional()\r\n   at System.Net.Security.SslStream.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)\r\n   at System.Net.Security.SslStream.EndProcessAuthentication(IAsyncResult result)\r\n   at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)\r\n   at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__65_1(IAsyncResult iar)\r\n   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)",
         "RemoteStackTraceString":null,
         "RemoteStackIndex":0,
         "ExceptionMethod":null,
         "HResult":-2146233087,
         "Source":"System.Private.CoreLib",
         "WatsonBuckets":null
      },
      "HelpLink":null,
      "Source":"System.Net.Http",
      "HResult":-2146233087
   },
   "HelpURL":null,
   "StackTraceString":"   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)\r\n   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)\r\n   at System.Threading.Tasks.Task`1.get_Result()\r\n   at Covid19.DataService.RawData.RawDataImportService.Get(String url) in E:\\Covid19\\Backend\\Covid19\\Covid19.DataService\\RawData\\RawDataImportService.cs:line 346\r\n   at Covid19.DataService.RawData.RawDataImportService.ImportECDPCData(DataSource source, IDictionary`2 populations, IEnumerable`1& locations, List`1& log) in E:\\Covid19\\Backend\\Covid19\\Covid19.DataService\\RawData\\RawDataImportService.cs:line 60\r\n   at Covid19.DataService.RawData.RawDataImportService.ImportData(DataSource source, IDictionary`2 populations, IEnumerable`1& locations, List`1& log) in E:\\Covid19\\Backend\\Covid19\\Covid19.DataService\\RawData\\RawDataImportService.cs:line 40",
   "RemoteStackTraceString":null,
   "RemoteStackIndex":0,
   "ExceptionMethod":null,
   "HResult":-2146233088,
   "Source":"System.Private.CoreLib",
   "WatsonBuckets":null,
   "InnerExceptions":[
      {
         "StackTrace":"   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)\r\n   at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)\r\n   at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n   at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)\r\n   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n   at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n   at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)",
         "Message":"The SSL connection could not be established, see inner exception.",
         "Data":{
            
         },
         "InnerException":{
            "ClassName":"System.Security.Authentication.AuthenticationException",
            "Message":"Authentication failed, see inner exception.",
            "Data":null,
            "InnerException":{
               "ClassName":"System.ComponentModel.Win32Exception",
               "Message":"The message received was unexpected or badly formatted.",
               "Data":null,
               "InnerException":null,
               "HelpURL":null,
               "StackTraceString":null,
               "RemoteStackTraceString":null,
               "RemoteStackIndex":0,
               "ExceptionMethod":null,
               "HResult":-2147467259,
               "Source":null,
               "WatsonBuckets":null,
               "NativeErrorCode":-2146893018
            },
            "HelpURL":null,
            "StackTraceString":"   at System.Net.Security.SslStream.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)\r\n   at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)\r\n   at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)\r\n   at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)\r\n   at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)\r\n   at System.Net.Security.SslStream.PartialFrameCallback(AsyncProtocolRequest asyncRequest)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Net.Security.SslStream.ThrowIfExceptional()\r\n   at System.Net.Security.SslStream.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)\r\n   at System.Net.Security.SslStream.EndProcessAuthentication(IAsyncResult result)\r\n   at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)\r\n   at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__65_1(IAsyncResult iar)\r\n   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)",
            "RemoteStackTraceString":null,
            "RemoteStackIndex":0,
            "ExceptionMethod":null,
            "HResult":-2146233087,
            "Source":"System.Private.CoreLib",
            "WatsonBuckets":null
         },
         "HelpLink":null,
         "Source":"System.Net.Http",
         "HResult":-2146233087
      }
   ]
}
Ayoub.A
  • 1,943
  • 3
  • 27
  • 34
  • https://stackoverflow.com/a/57234514/3645638 did you see this? – Svek Oct 31 '20 at 16:00
  • I would suspect your host is running an old version of something. can you log the issue from the handler? – Svek Oct 31 '20 at 16:16

1 Answers1

2

Quick and Dirty Solution

Although it's not the most elegant solution, but a quick and dirty way is to just call..

This is where you would put the fix your method

private HttpResponseMessage Get(string url)
{
    // HACK: set the policy here
    ServicePointManager.ServerCertificateValidationCallback +=
        (sender, cert, chain, sslPolicyErrors) => true; 

    // note:
    // also might be worth taking a look at DangerousAcceptAnyServerCertificateValidator

    var response = _httpClient.GetAsync(url).Result;

    int count = 0;

    while (count < 3 && response.IsSuccessStatusCode)
    {
        response = _httpClient.GetAsync(url).Result;
        count++;

    }

    return response;
}

Advanced Solution

A better approach would probably to create a named or typed HttpClient with a custom outgoing handler which is a class that inherits from DelegatingHandler.

For example

public class IgnoreSSLValidateDelegatingHandler : DelegatingHandler
{
    // this commented block could be useful if you want to allow a defined
    // group of certicates, rather than just anything out in the wild.
    // -------------------------------------------------------------------
    //private readonly X509CertificateCollection _certificates;
    //public IgnoreSSLValidateDelegatingHandler()
    //{
    //  _certificates = new X509CertificateCollection();
    //}

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        System.Threading.CancellationToken cancellationToken)
    {
        HttpMessageHandler handler = this.InnerHandler;

        while (handler is DelegatingHandler)
        {
            handler = ((DelegatingHandler)handler).InnerHandler;
        }

        if (handler is HttpClientHandler httpClientHandler
            && httpClientHandler.ServerCertificateCustomValidationCallback == null)
        {
            httpClientHandler
                .ServerCertificateCustomValidationCallback =
                    (message, cert, chain, errors) => true;
        }
        
        return base.SendAsync(request, cancellationToken);
    }
}
Svek
  • 12,350
  • 6
  • 38
  • 69
  • Thank you for your answer, but both approaches don't seem to be working. I edited my post by adding the entire exception body. – Ayoub.A Oct 31 '20 at 13:58