본문 바로가기
.Net

The underlying connection was closed – REST API call over HTTPS

by 올엠 2020. 11. 4.
반응형

https://www.youtube.com/watch?v=KW90zdq0il4

{System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send. ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
   at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
   at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
   --- End of inner exception stack trace ---
   at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
   at System.Net.FixedSizeReader.ReadPacket(Byte[] buffer, Int32 offset, Int32 count)
   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
   at System.Net.TlsStream.CallProcessAuthentication(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result)
   at System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size)
   at System.Net.PooledStream.Write(Byte[] buffer, Int32 offset, Int32 size)
   at System.Net.ConnectStream.WriteHeaders(Boolean async)
   --- End of inner exception stack trace ---
   at System.Net.WebClient.DownloadDataInternal(Uri address, WebRequest& request)
   at System.Net.WebClient.DownloadString(Uri address)
   at System.Net.WebClient.DownloadString(String address)
   at ConsoleApp6.Program.DownloadString(String address) in D:\Jshan\Visual Studio 2017\Projects\ConsoleApp6\ConsoleApp6\Program.cs:line 31
   at ConsoleApp6.Program.Main(String[] args) in D:\Jshan\Visual Studio 2017\Projects\ConsoleApp6\ConsoleApp6\Program.cs:line 12}

The sample code looks like this:

using System;
using System.Net;

namespace ConsoleApp6
{
    internal static class Program
    {
        private static void Main(string[] args)
        {
            //Add your user agent of choice. This is mine, just as an example.                   
            const string address = @"https rest api here";
            DownloadString(address);
            //Console.WriteLine(test);
        }

        private static void DownloadString(string address)
        {
            try
            {
                
                var client = new WebClient();

                var reply = client.DownloadString(address);

                Console.WriteLine(reply);
                Console.ReadLine();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                throw;
            }
        }
    }
}

Despite the use of the WebClient, HttpWebRequest, or WebRequest classes in C #, the same failure continued to occur.

The underlying connection was closed: An unexpected error occurred on a send.

The answer was in a secure connection by default in Windows. Basically TLS or SSL3 attempts to establish a secure connection. If the attempt fails, an issue occurs because the connection is blocked without negotiating the reconnection.

It is resolved by putting the following code before WebClient (or WebRequest or HttpWebRequest) is instantiated.

                var client = new WebClient();
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
                var reply = client.DownloadString(address);

That’s all, So simple is it?

반응형