System.Net.Http.HttpClient not timing out after set time - c#

I'm using HttpClient to handle web requests. I'll perform the request like so...
var response = await httpClient.PostAsync(Uri, stringContent);
The timeout is set in the http client setup and I then call it in the class with IHttpClientFactory dependency.
// Setup HttpClient
services.AddHttpClient("ApiName", client =>
{
client.BaseAddress = new Uri("BaseUri");
client.Timeout = new TimeSpan(0, 0, 8);
});
I've inspected httpClient before it runs to see if its using the correct API and it is, the timeout is set to 8 seconds. However, the request takes around a good 1-2 minutes to timeout. I'm not sure why this is happening.
I've tried using a CancellationToken like so...
var cts = new CancellationTokenSource();
cts.CancelAfter(8000);
var response = await httpClient.PostAsync(Uri, stringContent, cts.Token);
and waiting for the exception to occur but it still takes 1-2 minutes.

Based on the HttpClient.Timeout documentation, a DNS query may take up to 15 seconds to return or time out. However that does not explain the 1-2 minute delay you are seeing.
Have you looked at "Better timeout handling with HttpClient"? I don't know if it will work, but rather than using PostAsync you might try building the POST with HttpRequestMessage and use SendAsync instead, similar to the example in the article:
var request = new HttpRequestMessage(HttpMethod.Post, "http://foo/");
request.Content = stringContent;
request.SetTimeout(TimeSpan.FromSeconds(8)); // Uses HttpRequestExtensions from article
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(8));
var response = await client.SendAsync(request, cts.Token);

Related

UWP http client delay in getting response

I found this peculiar behaviour of UWP HttpClient.
For a simple get call of WCF service is taking time almost more than 100 seconds(happens for first few calls). I observed that the same service is way too faster in iOS and rest client.
Attaching the code, Please let me know, if i doing wrong.
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.UseCookies = true;
var client = new HttpClient(clientHandler);
client.Timeout = TimeSpan.FromSeconds(100);
client.DefaultRequestHeaders.Add("Accept", "application/json");
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get,
requestUri);
var response = await client.SendAsync(httpRequestMessage);
//Between these lines there is a delay, it doesnt fire time out
also. I tried with HttpCompletionOption. No luck
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
}
Any help will be really appreciated.
Thanks and Regards,
Rummy

Set automatic timeout based on number of http requests sent

I'm trying to develop an http proxy server for a UWP application using C# as a portable dll.However the retry timeout is 60 seconds independent of the number of requests sent, say 4 requests are sent but if it has to retry I have to wait for 60 seconds for a small number of tasks.Is there any way that I can automate how this retry timeout such that optimum timeout is used based on number of requests, maybe something​ declared globally can be used and called within the sendasync(used to send requests)?
In UWP, there are two HttpClient we can use to send HTTP request. They are System.Net.Http.HttpClient and Windows.Web.Http.HttpClient. I'm not sure which one you are using.
For System.Net.Http.HttpClient, there are two ways to set a timeout. To set a timeout for all requests made from that client, we can use HttpClient.Timeout property:
var myClient = new System.Net.Http.HttpClient();
myClient.Timeout = TimeSpan.FromSeconds(30);
To set a timeout on a single request, use the cancellation token pattern:
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(30));
var httpClient = new System.Net.Http.HttpClient();
var resourceUri = new Uri("http://www.contoso.com");
try
{
HttpResponseMessage response = await httpClient.GetAsync(resourceUri, cts.Token);
}
catch (TaskCanceledException ex)
{
// Handle request being canceled due to timeout.
}
catch (HttpRequestException ex)
{
// Handle other possible exceptions.
}
For Windows.Web.Http.HttpClient, there is no timeout property on the Windows.Web.Http.HttpClient type. As a result, you must use the cancellation token pattern shown above.
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(30));
var httpClient = new Windows.Web.Http.HttpClient();
var resourceUri = new Uri("http://www.contoso.com");
try
{
var response = await httpClient.GetAsync(resourceUri).AsTask(cts.Token);
}
catch (TaskCanceledException ex)
{
// Handle request being canceled due to timeout.
}
catch (Exception ex)
{
// Handle other possible exceptions.
}
For more info, please see Demystifying HttpClient APIs in the Universal Windows Platform.

HttpClient's SendAsync is very slow (Not a Proxy issue)

Currently, sending a POST message with HttpClient is taking ~600ms. This seems to be far longer than it should, as sending an identical POST with a C program I wrote inorder to test (using a simple socket) performed significantly better, about 37ms for the same action and significantly more code.
sw.Start();
HttpResponseMessage result = client.SendAsync(request).Result;
sw.Stop();
This was my measuring method. I am aware that I could be using an async function, and await instead of using the task Result, however there is nothing to worry about "blocking" in this case, and using await/async would be no faster since sending and receiving the messages would take the same amount of time asynchronously. Atleast, this is my understanding.
Here is an example of its use within a function :
public void makeAttempt(string attempt)
{
Stopwatch sw = new Stopwatch();
using (var request = new HttpRequestMessage() { Method = HttpMethod.Post })
{
request.RequestUri = new Uri("https://example.com/page?1");
request.Content = new StringContent("attempt-" + trys.ToString(), Encoding.UTF8, "application/x-www-form-urlencoded");
sw.Start();
HttpResponseMessage result = client.SendAsync(request).Result;
sw.Stop();
}
Console.WriteLine("Request took: " + sw.ElapsedMilliseconds.ToString() + "ms");
trys++;
}
Originally I also had the HttpClient & HttpClientHandler within using blocks in the same statement, however I read that HttpClient is meant to be reused over multiple requests, so I moved them to global scope and initialize them within the constructor, like so:
HttpClient client;
HttpClientHandler handler;
public Test(CookieContainer jar, WebHeaderCollection heads)
{
cookieJar = jar;
headers = heads;
handler = new HttpClientHandler() { CookieContainer = cookieJar, AllowAutoRedirect = true, Proxy = null, UseProxy = false };
client = new HttpClient(handler);
client.BaseAddress = new Uri("https://example.com/");
client.DefaultRequestHeaders.ExpectContinue = false;
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0");
}
Does anyone know what the cause of this could be, or how to improve the performance of this operation? Thank you in advance, and will keep everyone updated on anything I learn! Cheers!
I have backported the .NET Core 2.1 SocketsHttpHandler to .NET Framework and I observed significant performance improvements with the backported implementation compared to .NET Framework HttpClientHandler in some cases, notably when dozens of multiple requests are issued concurrently.

How to call web API from an http client using a small timeout

I'm working with two web API projects that get communicated. The first web API calls the second one using an HttpClient class.
What I would like to do is to set a short timeout (500 ms) when I call the second web API, and if I don't get response in that time, just to skip the next lines that process the result in the client, but continue processing the request at server side(second API).
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.Timeout = this.Timeout; // (500ms)
HttpResponseMessage response = client.PostAsJsonAsync(EndPoint, PostData).Result;
if (response.IsSuccessStatusCode)
{
return response.Content.ReadAsAsync<T>().Result;
}
else
{
throw new CustomException()
}
}
It works in the first API side, however in the second API(server), I get the following exceptions:
"A task was canceled."
"The operation was cancelled."
at System.Threading.CancellationToken.ThrowOperationCanceledException()
at System.Threading.CancellationToken.ThrowIfCancellationRequested()
I think it is caused by the small timeout of the call, that ends when the second API is still processing the result.
How could I avoid this behaviour in the second API and continue processing the request ?
Thanks in advance.
That is the expected behavior. When you set a timeout and the call does not respond in that amount of time, the task is canceled and that exception is thrown.
And by the way, do not use .Result. That will cause blocking. Mark your method async and use await.
The whole thing should look something like this:
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.Timeout = this.Timeout; // (500ms)
try
{
HttpResponseMessage response = await client.PostAsJsonAsync(EndPoint, PostData);
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsAsync<T>();
}
else
{
throw new CustomException()
}
}
catch (TaskCanceledException)
{
// request did not complete in 500ms.
return null; // or something else to indicate no data, move on
}
}

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.
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
}
You can use one of the variants of the various methods that accepts a CancellationToken.
If the cancel happens after the method's Task has completed, the cancellation is ignored and you can continue with e.g. processing the content from the result.
var client = new HttpClient();
var cancel = new CancellationTokenSource();
cancel.CancelAfter(TimeSpan.FromSeconds(10));
var resp = client.GetAsync("http://www.google.co.uk", cancel.Token).Result;
So, in the above, provided we get enough back from the server for the GetAsync to complete, the cancellation has no effect.

Categories

Resources