It has already happened to me a couple of times and every time I forget what the issue was and how to solve it. That’s why I decided to write a short post about it, so hopefully next time I will remember. đŸ™‚ The problem arises when making a few (independent) HTTP requests using C#’s
1 |
HttpWebRequest |
. At first it sounds like a very usual thing to do, but the mystical part of it is that the first few requests succeed and then at a certain point the others start timing out. You may be tempted to increase the
1 |
Timeout |
first, but you will soon understand that it does not solve the problem.
tl;dr
You most probably forget to call
1 |
Close() |
on the
1 |
HttpWebResponse |
object you get after calling
1 |
request.GetResponse() |
.
The issue
Let’s try to reproduce this issue in a very simple environment. Let’s create a console application, executing the following piece of code.
1 2 3 4 5 6 7 |
for (int i = 0; i < 3; i++) { Console.WriteLine("Start {0}", i); var request = (HttpWebRequest)WebRequest.Create("http://google.com"); var response = (HttpWebResponse)request.GetResponse(); Console.WriteLine("Finish {0}", i); } |
The first two iterations will be ok, while the third one will hang on. The problem is that .NET has a limited connections pool and cannot create a new connection, because you have occupied all of them. The default connections limit is defined by ServicePointManager.DefaultConnectionLimit. It is 2 for a console application and 10 for a server environment, f.x., ASP.NET. We can actually change this value, so that we could use more connections. NOTE: This is not the solution of this concrete problem!
1 2 3 4 5 6 7 8 9 10 11 |
Console.WriteLine("Default connections limit: {0}", ServicePointManager.DefaultConnectionLimit); ServicePointManager.DefaultConnectionLimit = 3; Console.WriteLine("New connections limit: {0}", ServicePointManager.DefaultConnectionLimit); for (int i = 0; i < ServicePointManager.DefaultConnectionLimit + 1; i++) { Console.WriteLine("Start {0}", i); var request = (HttpWebRequest)WebRequest.Create("http://google.com"); var response = (HttpWebResponse)request.GetResponse(); Console.WriteLine("Finish {0}", i); } |
The following will hang on the fourth iteration and will throw a
1 |
WebException |
for timing out.
Regular time-outs
If the very first requests times out, then the problem is most probably related to your connection with the remote host. In this case you cold use a tool like Wireshark to debug your connectivity.
The solution
As said earlier, you should close the response object in order to free the connection. You could manually call
1 |
response.Close() |
or use
1 |
using (var response = request.GetResponse()) { ... } |
as
1 |
WebResponse |
implements
1 |
IDisposable |
and it will automatically close the response on dispose.