5

I'm using .NET HttpClient to send requests to my server. I have set HttpClient.Timeout property to 10 seconds so i'm getting a A task was cancelled exception whenever the server fails to process my request in less than 10 seconds. Good until here.

However, if the server is shut down it takes for the HttpClient around ~20 seconds to return a proper exception such as the one in the picture. enter image description here

I would like to see this exception faster than 10 seconds to be able to distinguish between Server Down and Operation took too long scenarios. I can't find anything about this in msdn documentation. Is there any timeout that can be set on the HttpClient?

Here's how i'm constructing the HttpClient

 var webRequestHandler = new WebRequestHandler
        {
            UseProxy = false,
            Proxy = null,
            AllowPipelining = false,
            ContinueTimeout = TimeSpan.Zero,
            UseCookies = false,
            AllowAutoRedirect = false,
        };
 var httpClient = new HttpClient(webRequestHandler);
 httpClient.Timeout = timeout;

  httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "application/json");
  httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", userAgent);
  httpClient.DefaultRequestHeaders.ExpectContinue = false;
Dan Dinu
  • 32,492
  • 24
  • 78
  • 114
  • 1
    Just a little analogy that i want you to think about: If you're on the phone with someone and ask a question. Is there a reliable (fast/immediate) way for you to determine whether the person you're talking to has fallen asleep or is just thinking real hard? – MrPaulch Nov 20 '14 at 10:51
  • Logically what you are asking does not make sense, you can't know if you have not had a response because the server is down or because it has taken too long to process your request, you just haven't had a response. – Ben Robinson Nov 20 '14 at 10:51
  • 1
    I think logically it does make sense since there is a difference between having an HTTP response and a TCP connection. – AlexDev Nov 20 '14 at 11:04
  • Well, you may not have a reliable way to check if the person you are talking to has fallen or thinking, but if you have a rule for "hang up if I get no answer in 10 seconds", it should not take you 20 seconds to take action. – vtortola Nov 20 '14 at 11:34
  • Take a look at ServicePointManager, there are a few properties which might help you. Another option would be to use an HttpWebRequest, which has a timeout for the response to start and one for the data to arrive. – AlexDev Nov 20 '14 at 12:11

2 Answers2

14

This answer just extends @brz's example.

You can use this approach that does not block the thread ( Task.Wait blocks the thread)

var timeout = Task.Delay(10000); // 10 seconds timeout
var request = httpClient.GetAsync("http://www.google.com");

await Task.WhenAny(timeout, request); // wait for either timeout or the request

if (timeout.IsCompleted) // if the timeout ended first, then handle it
{
    // handle timeout
}

// otherwise continue processing the request result
var response = await request;
Community
  • 1
  • 1
vtortola
  • 34,709
  • 29
  • 161
  • 263
4

You can't handle this with timeouts, as mentioned in msdn:

A Domain Name System (DNS) query may take up to 15 seconds to return or time out. If your request contains a host name that requires resolution and you set Timeout to a value less than 15 seconds, it may take 15 seconds or more before a WebException is thrown to indicate a timeout on your request.

However, another approach would be wrapping your request in another task and handle timeout from there:

var task = Task.Run(() => { 
                var req = new HttpClient().GetAsync("http://www.google.com");
                if (!req.Wait(10000))//wait for 10 seconds
                    throw new TaskCanceledException(req);
            });
task.Wait();
brz
  • 5,926
  • 1
  • 18
  • 18