[C# Helper]
Index Books FAQ Contact About Rod
[Beginning Database Design Solutions, Second Edition]

[Beginning Software Engineering, Second Edition]

[Essential Algorithms, Second Edition]

[The Modern C# Challenge]

[WPF 3d, Three-Dimensional Graphics with WPF and C#]

[The C# Helper Top 100]

[Interview Puzzles Dissected]

[C# 24-Hour Trainer]

[C# 5.0 Programmer's Reference]

[MCSD Certification Toolkit (Exam 70-483): Programming in C#]

Title: Prevent "underlying connection was closed" errors in C#

[Prevent

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.

[Prevent

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 experiment with it and to see additional details.

© 2009-2023 Rocky Mountain Computer Consulting, Inc. All rights reserved.