I have one request for a specific domain that take a really long time to complete : 22 seconds in average. The request itself does not return a lot of data.
var httpClient = new HttpClient(); //instantiated at app start and reused
var request = new HttpRequestMessage(HttpMethod.Get, "http://www.somedomain.com");
var result = await httpClient.SendAsync(request); //take a really long time
After some debugging, it seems related to DNS. If I run the exact same request but replace domain name by IP, it's fast (< 200 ms).
It's also fast if I run the request a second time using same HttpClient
instance. However, if I run that second request after more than one minute it's slow again (probably because connections are closed automatically after 1 minute).
Is there a way to improve this ? (eg: to make sure resolved DNS entries would stay in cache for a long period). Also why is DNS so slow for that domain when using HttpClient
? If I try to access that domain using Chrome it's blazing fast (even after flushing DNS and clearing cache). A DNS lookup of that domain using an online service is also very fast. Reported TTL is 60 minutes.
EDIT: I have tried to increase ServicePointManager.DnsRefreshTimeout
(which is set by default to 2 minutes). But it does not help.
Calling Dns.GetHostEntry("somedomain.com")
is instantaneous and return the right IP. I don't know why request with HttpClient
are so slow.
CodePudding user response:
It's not only about caching DNS query. If you create new client for every request, then before every request both TCP and HTTP handshakes are made -- which makes your single request slow. This is probably the reason why subsequent requests with "old" agent are faster -- handshakes are only made before first request, but not before second one.
CodePudding user response:
I found what's wrong : That domain has a IPV6 address as well as IPV4. This can be confirmed by running the following code :
Dns.GetHostEntry("somedomain.com")
Connection using IPV6 throws an exception after some timeout (which explain why it's so slow). Solution I found so far is to force IPV4 by resolving domain myself :
var uri = new Uri("somedomain.com");
var builder = new UriBuilder(uri);
var addresses = await Dns.GetHostAddressesAsync(uri.Host);
builder.Host = addresses
.First(x => x.AddressFamily == AddressFamily.InterNetwork) //force IPV4
.ToString();
var request = new HttpRequestMessage(HttpMethod.Get, builder.Uri);
request.Host = uri.Host;
Maybe there is a better way. I can't use SocketsHttpHandler
since project is running .NET Framework 4.5