Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Differentiate time exceeded from no server response using HttpClient

Is there a way, using HttpClient, to differentiate a time-out "when we get no response from the server" from a "time exceeded" operation?

Let me explain our issue:

  • Case1: If we don't get any response from the server in 10 seconds then this is an issue.
  • Case2: If we get a response from the server, but the server continues to transfer data and it takes a while, maybe 30 seconds or more. Then this is not an issue.

Is there a way using .NET HttpClient class to handle this scenario? From what I tested specifying a TimeOut on HttpClient will put the same time-out for case1 and case2.

like image 378
Fabien Avatar asked Oct 20 '22 19:10

Fabien


1 Answers

Here is the solution I managed to do:

// Create the cancelation token, when we don't get any feedback from server within 20 seconds
var cancelHeadersToken = new CancellationTokenSource();
cancelHeadersToken.CancelAfter(TimeSpan.FromSeconds(20)); // if we don't receive server headers after 20 seconds then something went wrong

// We have another cancelation token, that allows the user to cancel the request, so here we create a linked token source which uses both tokens
var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(userCancelToken, cancelHeadersToken.Token);

// The linked token is then used in GetAsync and we use the overload which allows to specify the HttpCompletionOption
// We only want to receive headers and not all content
var httpMessage = await customClient.CustomizedHttpClient.GetAsync(address, HttpCompletionOption.ResponseHeadersRead, linkedToken.Token).ConfigureAwait(false);

// We can then download the content, and we still allow to cancel anything by the user
using (var memoryStream = new MemoryStream(100000)) { // 100ko by default
    using (var stream = await httpMessage.Content.ReadAsStreamAsync().ConfigureAwait(false)) {
        await stream.CopyToAsync(memoryStream, 10000, userCancelToken).ConfigureAwait(false); // copy to memory stream 10ko per 10ko
    }

    string data = "";
    if (memoryStream.Length > 0) {
        var headers = httpMessage.Content.Headers;
        Encoding encoding;
        if (headers != null && headers.ContentType != null && headers.ContentType.CharSet != null) {
            encoding = Encoding.GetEncoding(headers.ContentType.CharSet);
        } else {
            encoding = Encoding.UTF8;
        }
        data = encoding.GetString(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
    }
    // Then you do whatever you want with data
}               
like image 61
Fabien Avatar answered Oct 30 '22 19:10

Fabien