Update 2009-08-06: This issue was fixed in Windows 7 RC and Windows 7 RTM :)
I was going nuts yesterday night after I wrote a couple of unit tests that involved the C# HttpWebRequest class. For some strange reason it always takes 20-30 seconds to create a HttpWebRequest with an url and calling the GetResponse method on Windows 7. I was thinking maybe the server I'm contacting is kinda slow, but it was really fast in the browser. So maybe my SSD drive is messed up? Ok, tried on a normal HDD, same thing. Okay, then maybe TestDriven.net is doing something strange, lets write a simple console application. Wtf, still the same issue! Then I tried it on a different Windows 7 PC, same issue.
I gave up (was very late anyway) and went to work to test it again in the morning on my work PC (also Windows 7). Still the same freaking issue, it takes forever to get anything connected with HttpWebRequest and HttpWebResponse. Getting the actual data is like 30 times faster (and should not matter anyway), still slower than I remembered, but the issue was just in the following two lines (first line took 2-5s, second line 20-25s):
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse();
Maybe this isn't the right comic, but its always good to make fun of not-perfectly-working operating systems:
Back to the Problem: I rewrote my console test application again (from last night) and compiled it on my work PC:
using System;
using System.Net;
namespace TestHttpRequest
{
class Program
{
static void Main(string[] args)
{
//WTF is going on here? Takes 30s on Windows 7, <100ms on Windows Vista
string url = "http://www.google.com";
Console.WriteLine("Connecting: " + url);
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse();
Console.WriteLine("Connected ..");
if (httpResponse.StatusCode == HttpStatusCode.OK)
{
// Dummy
Console.WriteLine("Getting data ..");
httpResponse.GetResponseStream();
} // if
else
Console.WriteLine("Failed to get any data ..");
Console.WriteLine("Done ..");
}
}
}
Guess what, still the same issue, takes around 30 seconds to do this very simple job in Windows 7. Could not really figure out the real cause of this (I'm not really that interested, I just wanted to write a couple of unit tests to make some things easier), but it seems like the Conhost.exe file (Console Window Host) of Windows 7 is doing a lot while this is going on (I even have different Windows 7 versions installed, it is the same issue on all of them). Could not see any networking going on (maybe 0.01 kb every 5 seconds) either. If I completely disable networking the GetResponse immediately crashes (it does not take 2-3s for the WebRequest.Create to do its work, and the exception occurs instantly), but that is not really helpful because I wanted to test the response ..
Instead of guessing what this could be about I just wanted to make sure this is a problem with my Windows 7, so I gave my test console application to my colleague that is running Windows Vista and the thing ran in about 20ms, there is nothing wrong with the code, it runs perfectly fine on a non-Windows 7 machine!
So I tried the same stuff in different ways, like using the WebClient class, same result, still 30 seconds for the request.
// Same stuff with webclient
WebClient webClient = new WebClient();
Console.WriteLine("Downloading: " + url);
byte[] data = webClient.DownloadData(url);
Console.WriteLine("Done ..");
Next I implemented the same stuff with sockets (more specifically TcpClient, which is based on Sockets, but a little easier to use), which is kinda ugly and more work, but at least I finally got the response time I was looking for (<100ms). Microsoft should maybe look into this Windows 7 issue .. for my unit tests I can now use my own HttpWebResponse class and all problems are gone :)
// Another try, this time with TcpClient ..
TcpClient client = new TcpClient("www.google.com", 80);
// Get the stream from the tcp client (allows us to read and write)
NetworkStream stream = client.GetStream();
// Write the http request ourselfs (Note: Needs 2 empty lines at the end)
byte[] requestBytes = Encoding.ASCII.GetBytes(
@"GET / HTTP/1.1
Host: www.google.com
Connection: Close
");
// Send this ound
stream.Write(requestBytes, 0, requestBytes.Length);
stream.Flush();
// We can't use DataAvailable here because we don't know when the data
// will arrive. So just call ReadByte until it returns -1 and then
// we know we are done (Note: This will block our application,
// if you really care about performance write it asyncronly).
Console.WriteLine("Getting data ..");
string result = "";
int aByte = 0;
do
{
aByte = stream.ReadByte();
if (aByte >= 0)
result += (char)aByte;
} while (aByte >= 0);
Console.WriteLine("Result=" + result);
client.Close();