Prevent “underlying connection was closed” errors in C#


[underlying connection was closed]

This example shows how to fix the error “The underlying connection was closed” when downloading a response from a web page.

Background

The basic approach for downloading a result from a web page is simple. Create a new WebClient object and use its DownloadString to download a URL result as a string. The following code snippet shows this technique.

using (WebClient client = new WebClient())
{
    return client.DownloadString(url);
}

This works fine for some web sites, but for others you get one of the following error messages.


[underlying connection was closed]

This seems to be caused by the web site using one of the newer security protocols. The solution is to set the ServicePointManager class’s static SecurityProtocol property to an appropriate value.

In older versions of .NET, that enumeration has two values, Ssl3 (Secure Socket Layer 3.0) and Tls (Transport Layer Security 1.0). Newer versions of the enumeration also include the values Tls11 (TLS 1.1), Tls12 (TLS 1.2), and Tls13 (TLS 1.3).

In Visual Studio 2019 with .NET Framework 4.5, I managed to get the earlier code snippet to work by setting SecurityProtocol to SecurityProtocolType.SystemDefault. That value has the numeric value 0, but for some reason setting this property to 0 doesn’t seem to work in Visual Studio 2008. Presumably that’s because of some difference in the Framework versions.

Fortunately explicitly setting the value to allow the TLS 1.1 and TLS 1.2 protocols seems to work.

A Fake Enumeration

To avoid using magic numbers, I wanted to create an enumeration holding the possible protocol values. Unfortunately the SecurityProtocol property expects a value of type SecurityProtocolType. If you set it equal to an enumeration that you define, Visual Studio complains that it cannot convert your enumeration into the necessary type.

In C# you can specify an enumeration’s type, but it must be an integral type such as int, uint, or short, so you cannot make it have the type SecurityProtocolType.

To work around that, I created the following class to define the possible values.

public class Protocols
{
    public const SecurityProtocolType
        protocol_SystemDefault = 0,
        protocol_Ssl3 = (SecurityProtocolType)48,
        protocol_Tls = (SecurityProtocolType)192,
        protocol_Tls11 = (SecurityProtocolType)768,
        protocol_Tls12 = (SecurityProtocolType)3072;
}

This class simply defines the protocol values listed on Microsoft’s web page SecurityProtocolType Enum. (Interestingly this is one of the pages that will not return a result unless you set the SecurityProtocol property.)

The example’s Form1_Load event handler uses the following statement to set the SecurityProtocol.

ServicePointManager.SecurityProtocol =
    Protocols.protocol_Tls11 | Protocols.protocol_Tls12;

The SecurityProtocol is a mask, so you can use the | operator to allow multiple protocols. This code allows TLS 1.2 and TLS 1.3.

Conclusion

So that’s the technique. Set ServicePointManager.SecurityProtocol to a combination of the protocols that you want to allow when downloading a web result. The Protocols class defines values that you can use almost as if Protocols were an enumeration.

Download the example to see additional details and to experiment on your own.


Download Example   Follow me on Twitter   RSS feed   Donate




About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.
This entry was posted in internet, web and tagged , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.